Re-enable testUninstallAllUserCaCerts_failIfNotProfileOwner am: 536bf217ec am: 4f05412f41
am: c9591872c0

Change-Id: I19c1eb6c07dad2d03a4055cb2841eba992b33d35
diff --git a/OldCtsTestCaseList.mk b/OldCtsTestCaseList.mk
index 739bae0..f0bc3aa 100644
--- a/OldCtsTestCaseList.mk
+++ b/OldCtsTestCaseList.mk
@@ -270,7 +270,7 @@
     CtsAtraceHostTestCases \
     CtsCppToolsTestCases \
     CtsDevicePolicyManagerTestCases \
-    CtsDragAndDropHostTestCases \
+    CtsWindowManagerHostTestCases \
     CtsDumpsysHostTestCases \
     CtsHostsideNetworkTests \
     CtsJdwpSecurityHostTestCases \
diff --git a/apps/CameraITS/build/envsetup.sh b/apps/CameraITS/build/envsetup.sh
index bcf294a..7daf049 100644
--- a/apps/CameraITS/build/envsetup.sh
+++ b/apps/CameraITS/build/envsetup.sh
@@ -18,6 +18,7 @@
 # is correct).
 
 CAMERA_ITS_TOP=$PWD
+export CAMERA_ITS_TOP="$CAMERA_ITS_TOP"
 
 [[ "${BASH_SOURCE[0]}" != "${0}" ]] || \
     { echo ">> Script must be sourced with 'source $0'" >&2; exit 1; }
diff --git a/apps/CameraITS/pymodules/its/caps.py b/apps/CameraITS/pymodules/its/caps.py
index a33757d..d9270f7 100644
--- a/apps/CameraITS/pymodules/its/caps.py
+++ b/apps/CameraITS/pymodules/its/caps.py
@@ -394,6 +394,59 @@
             "android.edge.availableEdgeModes") and mode \
             in props["android.edge.availableEdgeModes"];
 
+
+def lens_calibrated(props):
+    """Returns whether lens position is calibrated or not.
+
+    android.lens.info.focusDistanceCalibration has 3 modes.
+    0: Uncalibrated
+    1: Approximate
+    2: Calibrated
+
+    Args:
+        props: Camera properties objects.
+
+    Returns:
+        Boolean.
+    """
+    return props.has_key("android.lens.info.focusDistanceCalibration") and \
+         props["android.lens.info.focusDistanceCalibration"] == 2
+
+
+def lens_approx_calibrated(props):
+    """Returns whether lens position is calibrated or not.
+
+    android.lens.info.focusDistanceCalibration has 3 modes.
+    0: Uncalibrated
+    1: Approximate
+    2: Calibrated
+
+    Args:
+        props: Camera properties objects.
+
+    Returns:
+        Boolean.
+    """
+    return props.has_key("android.lens.info.focusDistanceCalibration") and \
+        (props["android.lens.info.focusDistanceCalibration"] == 1 or
+         props["android.lens.info.focusDistanceCalibration"] == 2)
+
+
+def fixed_focus(props):
+    """Returns whether a device is fixed focus.
+
+    props[android.lens.info.minimumFocusDistance] == 0 is fixed focus
+
+    Args:
+        props: Camera properties objects.
+
+    Returns:
+        Boolean.
+    """
+    return props.has_key("android.lens.info.minimumFocusDistance") and \
+        props["android.lens.info.minimumFocusDistance"] == 0
+
+
 class __UnitTest(unittest.TestCase):
     """Run a suite of unit tests on this module.
     """
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index 0057eb7..97ab389 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -25,6 +25,8 @@
 import cStringIO
 import scipy.stats
 import copy
+import cv2
+import os
 
 DEFAULT_YUV_TO_RGB_CCM = numpy.matrix([
                                 [1.000,  0.000,  1.402],
@@ -720,6 +722,7 @@
     img = numpy.vstack(chs).T.reshape(h/f,w/f,chans)
     return img
 
+
 def compute_image_sharpness(img):
     """Calculate the sharpness of input image.
 
@@ -732,13 +735,74 @@
     """
     chans = img.shape[2]
     assert(chans == 1 or chans == 3)
-    luma = img
-    if (chans == 3):
+    if (chans == 1):
+        luma = img[:, :, 0]
+    elif (chans == 3):
         luma = 0.299 * img[:,:,0] + 0.587 * img[:,:,1] + 0.114 * img[:,:,2]
 
     [gy, gx] = numpy.gradient(luma)
     return numpy.average(numpy.sqrt(gy*gy + gx*gx))
 
+
+def scale_img(img, scale=1.0):
+    """Scale and image based on a real number scale factor."""
+    dim = (int(img.shape[1]*scale), int(img.shape[0]*scale))
+    return cv2.resize(img.copy(), dim, interpolation=cv2.INTER_AREA)
+
+
+def find_chart(chart, img, scale_start, scale_stop, scale_step):
+    """Find the chart in the image.
+
+    Args:
+        chart:          numpy array; chart image
+        img:            numpy array; camera image containing chart
+        scale_start:    float; start of scaling factor
+        scale_stop:     float; stop of scaling factor
+        scale_step:     float; step of scaling factor
+
+    Returns:
+        bounding box (top_right, bottom_left) coordinates in img
+    """
+    max_match = []
+    # check for normalized image
+    if numpy.amax(img) <= 1.0:
+        img = (img * 255.0).astype(numpy.uint8)
+    if len(img.shape) == 2:
+        img_gray = img.copy()
+    elif len(img.shape) == 3:
+        if img.shape[2] == 1:
+            img_gray = img[:, :, 0]
+        else:
+            img_gray = cv2.cvtColor(img.copy(), cv2.COLOR_RGB2GRAY)
+    print 'Finding chart in image...'
+    for scale in numpy.arange(scale_start, scale_stop, scale_step):
+        img_scaled = scale_img(img_gray, scale)
+        result = cv2.matchTemplate(img_scaled, chart, cv2.TM_CCOEFF)
+        _, opt_val, _, top_left_scaled = cv2.minMaxLoc(result)
+        # print out scale and match
+        print ' scale factor: %.3f, optimization val: %.f' % (scale, opt_val)
+        max_match.append((opt_val, top_left_scaled))
+
+    # determine if optimization results are valid
+    opt_values = [x[0] for x in max_match]
+    if 2.0*min(opt_values) > max(opt_values):
+        estring = ('Unable to find chart in scene!\n'
+                   'Check camera distance and self-reported '
+                   'pixel pitch, focal length and hyperfocal distance.')
+        raise its.error.Error(estring)
+    # find max and draw bbox
+    match_index = max_match.index(max(max_match, key=lambda x: x[0]))
+    scale = scale_start + scale_step * match_index
+    print 'Optimum scale factor: %.3f' %  scale
+    top_left_scaled = max_match[match_index][1]
+    h, w = chart.shape
+    bottom_right_scaled = (top_left_scaled[0] + w, top_left_scaled[1] + h)
+    top_left = (int(top_left_scaled[0]/scale), int(top_left_scaled[1]/scale))
+    bottom_right = (int(bottom_right_scaled[0]/scale),
+                    int(bottom_right_scaled[1]/scale))
+    return (top_left, bottom_right)
+
+
 class __UnitTest(unittest.TestCase):
     """Run a suite of unit tests on this module.
     """
@@ -755,7 +819,7 @@
             [ 7 8 9 ]   [ 0.3 ]   [ 5.0 ]
                mat         x         y
         """
-        mat = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
+        mat = numpy.array([[1,2,3], [4,5,6], [7,8,9]])
         x = numpy.array([0.1,0.2,0.3]).reshape(1,1,3)
         y = apply_matrix_to_image(x, mat).reshape(3).tolist()
         y_ref = [1.4,3.2,5.0]
@@ -763,7 +827,7 @@
         self.assertTrue(passed)
 
     def test_apply_lut_to_image(self):
-        """ Unit test for apply_lut_to_image.
+        """Unit test for apply_lut_to_image.
 
         Test by using a canned set of values on a 1x1 pixel image. The LUT will
         simply double the value of the index:
@@ -777,6 +841,29 @@
         passed = all([math.fabs(y[i] - y_ref[i]) < 0.001 for i in xrange(3)])
         self.assertTrue(passed)
 
+    def test_compute_image_sharpness(self):
+        """Unit test for compute_img_sharpness.
+
+        Test by using PNG of ISO12233 chart and blurring intentionally.
+        'sharpness' should drop off by sqrt(2) for 2x blur of image.
+
+        We do one level of blur as PNG image is not perfect.
+        """
+        yuv_full_scale = 1023.0
+        chart_file = os.path.join(os.environ['CAMERA_ITS_TOP'], 'pymodules',
+                                  'its', 'test_images', 'ISO12233.png')
+        chart = cv2.imread(chart_file, cv2.IMREAD_ANYDEPTH)
+        white_level = numpy.amax(chart).astype(float)
+        sharpness = {}
+        for j in [2, 4, 8]:
+            blur = cv2.blur(chart, (j, j))
+            blur = blur[:, :, numpy.newaxis]
+            sharpness[j] = yuv_full_scale * compute_image_sharpness(blur /
+                                                                    white_level)
+        self.assertTrue(numpy.isclose(sharpness[2]/sharpness[4],
+                                      numpy.sqrt(2), atol=0.1))
+        self.assertTrue(numpy.isclose(sharpness[4]/sharpness[8],
+                                      numpy.sqrt(2), atol=0.1))
+
 if __name__ == '__main__':
     unittest.main()
-
diff --git a/apps/CameraITS/pymodules/its/test_images/ISO12233.png b/apps/CameraITS/pymodules/its/test_images/ISO12233.png
new file mode 100644
index 0000000..f1ffce8
--- /dev/null
+++ b/apps/CameraITS/pymodules/its/test_images/ISO12233.png
Binary files differ
diff --git a/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py b/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
new file mode 100644
index 0000000..7c1b579
--- /dev/null
+++ b/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
@@ -0,0 +1,259 @@
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+import cv2
+import its.caps
+import its.device
+import its.image
+import its.objects
+import numpy as np
+
+NUM_IMGS = 12
+NUM_TRYS = 8
+FRAME_TIME_TOL = 10  # ms
+SHARPNESS_TOL = 0.10  # percentage
+POSITION_TOL = 0.10  # percentage
+CHART_FILE = os.path.join(os.environ['CAMERA_ITS_TOP'], 'pymodules', 'its',
+                          'test_images', 'ISO12233.png')
+CHART_HEIGHT = 16.5  # cm
+CHART_DISTANCE = 40.0  # cm
+CHART_SCALE_START = 0.75
+CHART_SCALE_STOP = 1.25
+CHART_SCALE_STEP = 0.05
+VGA_WIDTH = 640
+VGA_HEIGHT = 480
+NAME = os.path.basename(__file__).split('.')[0]
+
+
+def normalize_img(img):
+    """Normalize the image values to between 0 and 1.
+
+    Args:
+        img: 2-D numpy array of image values
+    Returns:
+        Normalized image
+    """
+    return (img - np.amin(img))/(np.amax(img) - np.amin(img))
+
+
+def find_chart_bbox(img, chart, scale_factor):
+    """Find the crop area for the chart."""
+    scale_start = CHART_SCALE_START * scale_factor
+    scale_stop = CHART_SCALE_STOP * scale_factor
+    scale_step = CHART_SCALE_STEP * scale_factor
+    bbox = its.image.find_chart(chart, img,
+                                scale_start, scale_stop, scale_step)
+    # convert bbox to (xnorm, ynorm, wnorm, hnorm)
+    wnorm = float((bbox[1][0]) - bbox[0][0]) / img.shape[1]
+    hnorm = float((bbox[1][1]) - bbox[0][1]) / img.shape[0]
+    xnorm = float(bbox[0][0]) / img.shape[1]
+    ynorm = float(bbox[0][1]) / img.shape[0]
+    return xnorm, ynorm, wnorm, hnorm
+
+
+def find_af_chart(cam, props, sensitivity, exp, af_fd):
+    """Take an AF image to find the chart location.
+
+    Args:
+        cam:    An open device session.
+        props:  Properties of cam
+        sensitivity: Sensitivity for the AF request as defined in
+                     android.sensor.sensitivity
+        exp:    Exposure time for the AF request as defined in
+                android.sensor.exposureTime
+        af_fd:  float; autofocus lens position
+    Returns:
+        xnorm:  float; x location normalized to [0, 1]
+        ynorm:  float; y location normalized to [0, 1]
+        wnorm:  float; width normalized to [0, 1]
+        hnorm:  float; height normalized to [0, 1]
+    """
+    # find maximum size 4:3 format
+    fmts = props['android.scaler.streamConfigurationMap']['availableStreamConfigurations']
+    fmts = [f for f in fmts if f['format'] == 256]
+    fmt = {'format': 'yuv', 'width': fmts[0]['width'],
+           'height': fmts[0]['height']}
+    req = its.objects.manual_capture_request(sensitivity, exp)
+    req['android.lens.focusDistance'] = af_fd
+    trys = 0
+    done = False
+    while not done:
+        print 'Waiting for lens to move to correct location...'
+        cap_chart = cam.do_capture(req, fmt)
+        done = (cap_chart['metadata']['android.lens.state'] == 0)
+        print ' status: ', done
+        trys += 1
+        if trys == NUM_TRYS:
+            raise its.error.Error('Error: cannot settle lens in %d trys!'
+                                  % (trys))
+    y, _, _ = its.image.convert_capture_to_planes(cap_chart, props)
+    its.image.write_image(y, '%s_AF_image.jpg' % NAME)
+    template = cv2.imread(CHART_FILE, cv2.IMREAD_ANYDEPTH)
+    focal_l = cap_chart['metadata']['android.lens.focalLength']
+    pixel_pitch = (props['android.sensor.info.physicalSize']['height'] /
+                   y.shape[0])
+    print ' Chart distance: %.2fcm' % CHART_DISTANCE
+    print ' Chart height: %.2fcm' % CHART_HEIGHT
+    print ' Focal length: %.2fmm' % focal_l
+    print ' Pixel pitch: %.2fum' % (pixel_pitch*1E3)
+    print ' Template height: %d' % template.shape[0]
+    chart_pixel_h = CHART_HEIGHT * focal_l / (CHART_DISTANCE * pixel_pitch)
+    scale_factor = template.shape[0] / chart_pixel_h
+    print 'Chart/image scale factor = %.2f' % scale_factor
+    xnorm, ynorm, wnorm, hnorm = find_chart_bbox(y, template, scale_factor)
+    chart = its.image.get_image_patch(y, xnorm, ynorm, wnorm, hnorm)
+    its.image.write_image(chart, '%s_AF_chart.jpg' % NAME)
+    return xnorm, ynorm, wnorm, hnorm
+
+
+def test_lens_movement_reporting(cam, props, fmt, sensitivity, exp, af_fd):
+    """Return fd, sharpness, lens state of the output images.
+
+    Args:
+        cam: An open device session.
+        props: Properties of cam
+        fmt: dict; capture format
+        sensitivity: Sensitivity for the 3A request as defined in
+            android.sensor.sensitivity
+        exp: Exposure time for the 3A request as defined in
+            android.sensor.exposureTime
+        af_fd: Focus distance for the 3A request as defined in
+            android.lens.focusDistance
+
+    Returns:
+        Object containing reported sharpness of the output image, keyed by
+        the following string:
+            'sharpness'
+    """
+
+    print 'Take AF image for chart locator.'
+    xnorm, ynorm, wnorm, hnorm = find_af_chart(cam, props, sensitivity,
+                                               exp, af_fd)
+    data_set = {}
+    white_level = int(props['android.sensor.info.whiteLevel'])
+    min_fd = props['android.lens.info.minimumFocusDistance']
+    fds = [af_fd, min_fd]
+    fds = sorted(fds * NUM_IMGS)
+    reqs = []
+    for i, fd in enumerate(fds):
+        reqs.append(its.objects.manual_capture_request(sensitivity, exp))
+        reqs[i]['android.lens.focusDistance'] = fd
+    cap = cam.do_capture(reqs, fmt)
+    for i, _ in enumerate(reqs):
+        data = {'fd': fds[i]}
+        data['loc'] = cap[i]['metadata']['android.lens.focusDistance']
+        data['lens_moving'] = (cap[i]['metadata']['android.lens.state']
+                               == 1)
+        timestamp = cap[i]['metadata']['android.sensor.timestamp']
+        if i == 0:
+            timestamp_init = timestamp
+        timestamp -= timestamp_init
+        timestamp *= 1E-6
+        data['timestamp'] = timestamp
+        print ' focus distance (diopters): %.3f' % data['fd']
+        print ' current lens location (diopters): %.3f' % data['loc']
+        print ' lens moving %r' % data['lens_moving']
+        y, _, _ = its.image.convert_capture_to_planes(cap[i], props)
+        chart = normalize_img(its.image.get_image_patch(y, xnorm, ynorm,
+                                                        wnorm, hnorm))
+        its.image.write_image(chart, '%s_i=%d_chart.jpg' % (NAME, i))
+        data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+        print 'Chart sharpness: %.1f\n' % data['sharpness']
+        data_set[i] = data
+    return data_set
+
+
+def main():
+    """Test if focus distance is properly reported.
+
+    Capture images at a variety of focus locations.
+    """
+
+    print '\nStarting test_lens_movement_reporting.py'
+    with its.device.ItsSession() as cam:
+        props = cam.get_camera_properties()
+        its.caps.skip_unless(not its.caps.fixed_focus(props))
+        its.caps.skip_unless(its.caps.lens_approx_calibrated(props))
+        min_fd = props['android.lens.info.minimumFocusDistance']
+        fmt = {'format': 'yuv', 'width': VGA_WIDTH, 'height': VGA_HEIGHT}
+
+        # Get proper sensitivity, exposure time, and focus distance with 3A.
+        s, e, _, _, fd = cam.do_3a(get_results=True)
+
+        # Get sharpness for each focal distance
+        d = test_lens_movement_reporting(cam, props, fmt, s, e, fd)
+        for k in sorted(d):
+            print ('i: %d\tfd: %.3f\tlens location (diopters): %.3f \t'
+                   'sharpness: %.1f  \tlens_moving: %r \t'
+                   'timestamp: %.1fms' % (k, d[k]['fd'], d[k]['loc'],
+                                          d[k]['sharpness'],
+                                          d[k]['lens_moving'],
+                                          d[k]['timestamp']))
+
+        # assert frames are consecutive
+        print 'Asserting frames are consecutive'
+        times = [v['timestamp'] for v in d.itervalues()]
+        diffs = np.gradient(times)
+        print diffs
+        assert np.isclose(np.amax(diffs)-np.amax(diffs), 0, atol=FRAME_TIME_TOL)
+
+        # remove data when lens is moving
+        for k in sorted(d):
+            if d[k]['lens_moving']:
+                del d[k]
+
+        # split data into min_fd and af data for processing
+        d_min_fd = {}
+        d_af_fd = {}
+        for k in sorted(d):
+            if d[k]['fd'] == min_fd:
+                d_min_fd[k] = d[k]
+            if d[k]['fd'] == fd:
+                d_af_fd[k] = d[k]
+
+        # assert reported locations are close at af_fd
+        print 'Asserting lens location of af_fd data'
+        min_loc = min([v['loc'] for v in d_af_fd.itervalues()])
+        max_loc = max([v['loc'] for v in d_af_fd.itervalues()])
+        assert np.isclose(min_loc, max_loc, rtol=POSITION_TOL)
+        # assert reported sharpness is close at af_fd
+        print 'Asserting sharpness of af_fd data'
+        min_sharp = min([v['sharpness'] for v in d_af_fd.itervalues()])
+        max_sharp = max([v['sharpness'] for v in d_af_fd.itervalues()])
+        assert np.isclose(min_sharp, max_sharp, rtol=SHARPNESS_TOL)
+        # assert reported location is close to assign location for af_fd
+        print 'Asserting lens location close to assigned fd for af_fd data'
+        assert np.isclose(d_af_fd[0]['loc'], d_af_fd[0]['fd'],
+                          rtol=POSITION_TOL)
+
+        # assert reported location is close for min_fd captures
+        print 'Asserting lens location similar min_fd data'
+        min_loc = min([v['loc'] for v in d_min_fd.itervalues()])
+        max_loc = max([v['loc'] for v in d_min_fd.itervalues()])
+        assert np.isclose(min_loc, max_loc, rtol=POSITION_TOL)
+        # assert reported sharpness is close at min_fd
+        print 'Asserting sharpness of min_fd data'
+        min_sharp = min([v['sharpness'] for v in d_min_fd.itervalues()])
+        max_sharp = max([v['sharpness'] for v in d_min_fd.itervalues()])
+        assert np.isclose(min_sharp, max_sharp, rtol=SHARPNESS_TOL)
+        # assert reported location is close to assign location for min_fd
+        print 'Asserting lens location close to assigned fd for min_fd data'
+        assert np.isclose(d_min_fd[NUM_IMGS*2-1]['loc'],
+                          d_min_fd[NUM_IMGS*2-1]['fd'], rtol=POSITION_TOL)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 52780eb..d6dca72 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -58,7 +58,7 @@
         "scene0" : None,
         "scene1" : "A grey card covering at least the middle 30% of the scene",
         "scene2" : "A picture containing human faces",
-        "scene3" : "A chart containing sharp edges like ISO 12233",
+        "scene3" : "The ISO 12233 chart",
         "scene4" : "A specific test page of a circle covering at least the "
                    "middle 50% of the scene. See CameraITS.pdf section 2.3.4 "
                    "for more details",
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 83f99c5..7b3a328 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -2200,6 +2200,20 @@
             </intent-filter>
         </activity-alias>
 
+        <!-- 6DoF sensor test -->
+        <activity
+                android:name="com.android.cts.verifier.sensors.sixdof.Activities.StartActivity"
+                android:label="@string/six_dof_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.cts.intent.category.MANUAL_TEST"/>
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
+        </activity>
+        <activity
+                android:name="com.android.cts.verifier.sensors.sixdof.Activities.TestActivity"
+                android:label="@string/title_activity_cts">
+        </activity>
     </application>
 
 </manifest>
diff --git a/apps/CtsVerifier/res/drawable-hdpi/ic_place_white_24dp.png b/apps/CtsVerifier/res/drawable-hdpi/ic_place_white_24dp.png
new file mode 100644
index 0000000..7c281c3
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-hdpi/ic_place_white_24dp.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable-hdpi/ic_save.png b/apps/CtsVerifier/res/drawable-hdpi/ic_save.png
new file mode 100644
index 0000000..a046efc
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-hdpi/ic_save.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable-mdpi/ic_place_white_24dp.png b/apps/CtsVerifier/res/drawable-mdpi/ic_place_white_24dp.png
new file mode 100644
index 0000000..933eb51
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-mdpi/ic_place_white_24dp.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable-mdpi/ic_save.png b/apps/CtsVerifier/res/drawable-mdpi/ic_save.png
new file mode 100644
index 0000000..c36e990
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-mdpi/ic_save.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable-xhdpi/ic_place_white_24dp.png b/apps/CtsVerifier/res/drawable-xhdpi/ic_place_white_24dp.png
new file mode 100644
index 0000000..814ca8d
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-xhdpi/ic_place_white_24dp.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable-xhdpi/ic_save.png b/apps/CtsVerifier/res/drawable-xhdpi/ic_save.png
new file mode 100644
index 0000000..94d699e
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-xhdpi/ic_save.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable-xxhdpi/ic_place_white_24dp.png b/apps/CtsVerifier/res/drawable-xxhdpi/ic_place_white_24dp.png
new file mode 100644
index 0000000..078b10d
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-xxhdpi/ic_place_white_24dp.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable-xxhdpi/ic_save.png b/apps/CtsVerifier/res/drawable-xxhdpi/ic_save.png
new file mode 100644
index 0000000..5a0fbe4
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-xxhdpi/ic_save.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable-xxxhdpi/ic_place_white_24dp.png b/apps/CtsVerifier/res/drawable-xxxhdpi/ic_place_white_24dp.png
new file mode 100644
index 0000000..8bcb6f6
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-xxxhdpi/ic_place_white_24dp.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable-xxxhdpi/ic_save.png b/apps/CtsVerifier/res/drawable-xxxhdpi/ic_save.png
new file mode 100644
index 0000000..264ce97
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable-xxxhdpi/ic_save.png
Binary files differ
diff --git a/apps/CtsVerifier/res/drawable/round_button.xml b/apps/CtsVerifier/res/drawable/round_button.xml
new file mode 100644
index 0000000..af5bff3
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable/round_button.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:top="8px">
+        <layer-list>
+            <item>
+                <shape android:shape="oval">
+                    <solid android:color="#08000000"/>
+                    <padding
+                            android:bottom="3px"
+                            android:left="3px"
+                            android:right="3px"
+                            android:top="3px"
+                    />
+                </shape>
+            </item>
+            <item>
+                <shape android:shape="oval">
+                    <solid android:color="#09000000"/>
+                    <padding
+                            android:bottom="2px"
+                            android:left="2px"
+                            android:right="2px"
+                            android:top="2px"
+                    />
+                </shape>
+            </item>
+            <item>
+                <shape android:shape="oval">
+                    <solid android:color="#10000000"/>
+                    <padding
+                            android:bottom="2px"
+                            android:left="2px"
+                            android:right="2px"
+                            android:top="2px"
+                    />
+                </shape>
+            </item>
+            <item>
+                <shape android:shape="oval">
+                    <solid android:color="#11000000"/>
+                    <padding
+                            android:bottom="1px"
+                            android:left="1px"
+                            android:right="1px"
+                            android:top="1px"
+                    />
+                </shape>
+            </item>
+            <item>
+                <shape android:shape="oval">
+                    <solid android:color="#12000000"/>
+                    <padding
+                            android:bottom="1px"
+                            android:left="1px"
+                            android:right="1px"
+                            android:top="1px"
+                    />
+                </shape>
+            </item>
+            <item>
+                <shape android:shape="oval">
+                    <solid android:color="#13000000"/>
+                    <padding
+                            android:bottom="1px"
+                            android:left="1px"
+                            android:right="1px"
+                            android:top="1px"
+                    />
+                </shape>
+            </item>
+            <item>
+                <shape android:shape="oval">
+                    <solid android:color="#14000000"/>
+                    <padding
+                            android:bottom="1px"
+                            android:left="1px"
+                            android:right="1px"
+                            android:top="1px"
+                    />
+                </shape>
+            </item>
+            <item>
+                <shape android:shape="oval">
+                    <solid android:color="#15000000"/>
+                    <padding
+                            android:bottom="1px"
+                            android:left="1px"
+                            android:right="1px"
+                            android:top="1px"
+                    />
+                </shape>
+            </item>
+
+            <item >
+                <shape android:shape="oval">
+                    <solid android:color="#00bfa5" />
+                </shape>
+
+            </item>
+
+        </layer-list>
+    </item>
+
+
+</layer-list>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout-port/fragment_accuracy.xml b/apps/CtsVerifier/res/layout-port/fragment_accuracy.xml
new file mode 100644
index 0000000..4ac4cdb
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-port/fragment_accuracy.xml
@@ -0,0 +1,59 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:orientation="vertical">
+
+        <!-- Deliberately empty so that we can add camera preview to it dynamically-->
+        <LinearLayout
+                android:layout_width="match_parent"
+                android:orientation="vertical"
+                android:layout_weight=".5"
+                android:layout_height="0dp"
+                android:id="@+id/llCamera">
+        </LinearLayout>
+
+        <RelativeLayout
+                android:padding="4dp"
+                android:layout_width="match_parent"
+                android:orientation="vertical"
+                android:layout_weight=".5"
+                android:layout_height="0dp">
+
+            <include layout="@layout/verifier_buttons"/>
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textSize="17sp"
+                    android:layout_below="@+id/llPassFail"
+                    android:id="@+id/tvObjective"/>
+
+            <TextView
+                    android:layout_below="@+id/tvObjective"
+                    android:paddingTop="20dp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/tvTranslations"/>
+
+            <TextView
+                    android:paddingTop="4dp"
+                    android:layout_below="@+id/tvTranslations"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/tvMarkers"/>
+        </RelativeLayout>
+    </LinearLayout>
+
+    <ImageButton
+            android:id="@+id/fabPlaceWaypoint"
+            android:layout_width="70dp"
+            android:layout_height="70dp"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_margin="16dp"
+            android:background="@drawable/round_button"
+            android:src="@drawable/ic_place_white_24dp"/>
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout-port/fragment_complex_movement.xml b/apps/CtsVerifier/res/layout-port/fragment_complex_movement.xml
new file mode 100644
index 0000000..d2c40c7
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-port/fragment_complex_movement.xml
@@ -0,0 +1,52 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:orientation="vertical">
+
+        <!-- Deliberately empty so that we can add camera preview to it dynamically-->
+        <LinearLayout
+                android:layout_width="match_parent"
+                android:orientation="vertical"
+                android:layout_weight=".5"
+                android:layout_height="0dp"
+                android:id="@+id/llCamera">
+        </LinearLayout>
+
+        <RelativeLayout
+                android:padding="4dp"
+                android:layout_width="match_parent"
+                android:orientation="vertical"
+                android:layout_weight=".5"
+                android:layout_height="0dp">
+
+            <include layout="@layout/verifier_buttons"/>
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textSize="17sp"
+                    android:layout_below="@+id/llPassFail"
+                    android:id="@+id/tvObjective"/>
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@+id/tvObjective"
+                    android:id="@+id/tvRings"/>
+
+        </RelativeLayout>
+    </LinearLayout>
+
+    <ImageButton
+            android:id="@+id/fabPlaceWaypoint"
+            android:layout_width="70dp"
+            android:layout_height="70dp"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_margin="16dp"
+            android:background="@drawable/round_button"
+            android:src="@drawable/ic_place_white_24dp"/>
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout-port/fragment_robustness.xml b/apps/CtsVerifier/res/layout-port/fragment_robustness.xml
new file mode 100644
index 0000000..b825082
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-port/fragment_robustness.xml
@@ -0,0 +1,61 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:orientation="vertical">
+
+        <!-- Deliberately empty so that we can add camera preview to it dynamically-->
+        <LinearLayout
+                android:layout_width="match_parent"
+                android:orientation="vertical"
+                android:layout_weight=".5"
+                android:layout_height="0dp"
+                android:id="@+id/llCamera">
+        </LinearLayout>
+
+        <RelativeLayout
+                android:padding="4dp"
+                android:layout_width="match_parent"
+                android:orientation="vertical"
+                android:layout_weight=".5"
+                android:layout_height="0dp">
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textSize="17sp"
+                    android:layout_below="@+id/llPassFail"
+                    android:id="@+id/tvObjective"/>
+
+            <TextView
+                    android:layout_below="@+id/tvObjective"
+                    android:paddingTop="20dp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/tvTimer"/>
+
+            <TextView
+                    android:id="@+id/tvPassColour"
+                    android:layout_width="match_parent"
+                    android:layout_height="50dp"
+                    android:layout_marginTop="50dp"
+                    android:layout_below="@id/tvTimer"
+                    android:background="@color/green"/>
+
+            <include layout="@layout/verifier_buttons"/>
+
+        </RelativeLayout>
+    </LinearLayout>
+
+    <ImageButton
+            android:id="@+id/fabPlaceWaypoint"
+            android:layout_width="70dp"
+            android:layout_height="70dp"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_margin="16dp"
+            android:background="@drawable/round_button"
+            android:src="@drawable/ic_place_white_24dp"/>
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/activity_cts.xml b/apps/CtsVerifier/res/layout/activity_cts.xml
new file mode 100644
index 0000000..ef1459e
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/activity_cts.xml
@@ -0,0 +1,12 @@
+<RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:keepScreenOn="true">
+
+    <FrameLayout
+            android:id="@+id/contentFragment"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"/>
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/activity_start.xml b/apps/CtsVerifier/res/layout/activity_start.xml
new file mode 100644
index 0000000..e7e7273
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/activity_start.xml
@@ -0,0 +1,25 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:paddingLeft="@dimen/activity_horizontal_margin"
+                android:paddingRight="@dimen/activity_horizontal_margin"
+                android:paddingTop="@dimen/activity_vertical_margin"
+                android:paddingBottom="@dimen/activity_vertical_margin"
+                tools:context=".StartActivity">
+
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:id="@+id/tvDesc"
+            android:text="@string/overall_instructions"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/tvDesc"
+            android:layout_centerHorizontal="true"
+            android:id="@+id/btnStart"
+            android:text="@string/start"/>
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/dialog_result_accuracy.xml b/apps/CtsVerifier/res/layout/dialog_result_accuracy.xml
new file mode 100644
index 0000000..c499248
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/dialog_result_accuracy.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal">
+
+        <TextView android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:gravity="center"
+                  android:text="@string/waypoint_differences"
+                  android:layout_weight="1"/>
+        <TextView android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:gravity="center"
+                  android:id="@+id/tvWaypointResult"
+                  android:layout_weight="1"/>
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingTop="10dp"
+                  android:orientation="horizontal">
+
+        <TextView android:layout_width="0dp"
+                  android:gravity="center"
+                  android:text="@string/path_differences"
+                  android:layout_height="wrap_content"
+                  android:layout_weight="1"/>
+        <TextView android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:gravity="center"
+                  android:id="@+id/tvPathResult"
+                  android:layout_weight="1"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/dialog_result_complex_movement.xml b/apps/CtsVerifier/res/layout/dialog_result_complex_movement.xml
new file mode 100644
index 0000000..f3946ec
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/dialog_result_complex_movement.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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_width="match_parent"
+                  android:paddingTop="10dp"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal">
+
+        <TextView android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:gravity="center"
+                  android:text="@string/waypoint_differences"
+                  android:layout_weight="1"/>
+        <TextView android:layout_width="0dp"
+                  android:gravity="center"
+                  android:id="@+id/tvWaypointResult"
+                  android:layout_height="wrap_content"
+                  android:layout_weight="1"/>
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:paddingTop="10dp"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal">
+
+        <TextView android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:gravity="center"
+                  android:text="@string/rings"
+                  android:layout_weight="1"/>
+        <TextView android:layout_width="0dp"
+                  android:gravity="center"
+                  android:id="@+id/tvRingsResult"
+                  android:layout_height="wrap_content"
+                  android:layout_weight="1"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/dialog_result_robustness.xml b/apps/CtsVerifier/res/layout/dialog_result_robustness.xml
new file mode 100644
index 0000000..50c6bb9
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/dialog_result_robustness.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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_width="match_parent"
+                  android:paddingTop="10dp"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal">
+
+        <TextView android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:gravity="center"
+                  android:text="@string/waypoint_differences"
+                  android:layout_weight="1"/>
+        <TextView android:layout_width="0dp"
+                  android:gravity="center"
+                  android:id="@+id/tvWaypointResult"
+                  android:layout_height="wrap_content"
+                  android:layout_weight="1"/>
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:paddingTop="10dp"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal">
+
+        <TextView android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:gravity="center"
+                  android:text="@string/path_differences"
+                  android:layout_weight="1"/>
+        <TextView android:layout_width="0dp"
+                  android:gravity="center"
+                  android:id="@+id/tvPathResult"
+                  android:layout_height="wrap_content"
+                  android:layout_weight="1"/>
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:paddingTop="10dp"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal">
+
+        <TextView android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:gravity="center"
+                  android:text="@string/time"
+                  android:layout_weight="1"/>
+        <TextView android:layout_width="0dp"
+                  android:gravity="center"
+                  android:id="@+id/tvTimeResult"
+                  android:layout_height="wrap_content"
+                  android:layout_weight="1"/>
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:paddingTop="10dp"
+                  android:layout_height="wrap_content"
+                  android:orientation="horizontal">
+
+        <TextView android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:gravity="center"
+                  android:text="@string/rotation_result"
+                  android:layout_weight="1"/>
+        <TextView android:layout_width="0dp"
+                  android:gravity="center"
+                  android:id="@+id/tvRotationResult"
+                  android:layout_height="wrap_content"
+                  android:layout_weight="1"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/fragment_accuracy.xml b/apps/CtsVerifier/res/layout/fragment_accuracy.xml
new file mode 100644
index 0000000..c5c8b0b
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/fragment_accuracy.xml
@@ -0,0 +1,58 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="match_parent">
+
+        <!-- Deliberately empty so that we can add camera preview to it dynamically-->
+        <LinearLayout
+                android:layout_width="0dp"
+                android:orientation="vertical"
+                android:layout_weight=".75"
+                android:layout_height="match_parent"
+                android:id="@+id/llCamera">
+        </LinearLayout>
+
+        <RelativeLayout
+                android:padding="4dp"
+                android:layout_width="0dp"
+                android:orientation="vertical"
+                android:layout_weight=".25"
+                android:layout_height="match_parent">
+
+            <include layout="@layout/verifier_buttons"/>
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textSize="17sp"
+                    android:layout_below="@+id/llPassFail"
+                    android:id="@+id/tvObjective"/>
+
+            <TextView
+                    android:layout_below="@+id/tvObjective"
+                    android:paddingTop="20dp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/tvTranslations"/>
+
+            <TextView
+                    android:paddingTop="4dp"
+                    android:layout_below="@+id/tvTranslations"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/tvMarkers"/>
+        </RelativeLayout>
+    </LinearLayout>
+
+    <ImageButton
+            android:id="@+id/fabPlaceWaypoint"
+            android:layout_width="70dp"
+            android:layout_height="70dp"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_margin="16dp"
+            android:background="@drawable/round_button"
+            android:src="@drawable/ic_place_white_24dp"/>
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/fragment_complex_movement.xml b/apps/CtsVerifier/res/layout/fragment_complex_movement.xml
new file mode 100644
index 0000000..f0c30e2
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/fragment_complex_movement.xml
@@ -0,0 +1,51 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="match_parent">
+
+        <!-- Deliberately empty so that we can add camera preview to it dynamically-->
+        <LinearLayout
+                android:layout_width="0dp"
+                android:orientation="vertical"
+                android:layout_weight=".75"
+                android:layout_height="match_parent"
+                android:id="@+id/llCamera">
+        </LinearLayout>
+
+        <RelativeLayout
+                android:padding="4dp"
+                android:layout_width="0dp"
+                android:orientation="vertical"
+                android:layout_weight=".25"
+                android:layout_height="match_parent">
+
+            <include layout="@layout/verifier_buttons"/>
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textSize="17sp"
+                    android:layout_below="@+id/llPassFail"
+                    android:id="@+id/tvObjective"/>
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@+id/tvObjective"
+                    android:id="@+id/tvRings"/>
+
+        </RelativeLayout>
+    </LinearLayout>
+
+    <ImageButton
+            android:id="@+id/fabPlaceWaypoint"
+            android:layout_width="70dp"
+            android:layout_height="70dp"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_margin="16dp"
+            android:background="@drawable/round_button"
+            android:src="@drawable/ic_place_white_24dp"/>
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/fragment_robustness.xml b/apps/CtsVerifier/res/layout/fragment_robustness.xml
new file mode 100644
index 0000000..13f1e89
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/fragment_robustness.xml
@@ -0,0 +1,60 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="match_parent">
+
+        <!-- Deliberately empty so that we can add camera preview to it dynamically-->
+        <LinearLayout
+                android:layout_width="0dp"
+                android:orientation="vertical"
+                android:layout_weight=".75"
+                android:layout_height="match_parent"
+                android:id="@+id/llCamera">
+        </LinearLayout>
+
+        <RelativeLayout
+                android:padding="4dp"
+                android:layout_width="0dp"
+                android:orientation="vertical"
+                android:layout_weight=".25"
+                android:layout_height="match_parent">
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textSize="17sp"
+                    android:layout_below="@+id/llPassFail"
+                    android:id="@+id/tvObjective"/>
+
+            <TextView
+                    android:layout_below="@+id/tvObjective"
+                    android:paddingTop="20dp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/tvTimer"/>
+
+            <TextView
+                    android:id="@+id/tvPassColour"
+                    android:layout_width="match_parent"
+                    android:layout_height="50dp"
+                    android:layout_marginTop="50dp"
+                    android:layout_below="@id/tvTimer"
+                    android:background="@color/green"/>
+
+            <include layout="@layout/verifier_buttons"/>
+
+        </RelativeLayout>
+    </LinearLayout>
+
+    <ImageButton
+            android:id="@+id/fabPlaceWaypoint"
+            android:layout_width="70dp"
+            android:layout_height="70dp"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_margin="16dp"
+            android:background="@drawable/round_button"
+            android:src="@drawable/ic_place_white_24dp"/>
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/fragment_start_phase.xml b/apps/CtsVerifier/res/layout/fragment_start_phase.xml
new file mode 100644
index 0000000..73c5802
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/fragment_start_phase.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:paddingLeft="@dimen/activity_horizontal_margin"
+              android:paddingRight="@dimen/activity_horizontal_margin"
+              android:paddingTop="@dimen/activity_vertical_margin"
+              android:paddingBottom="@dimen/activity_vertical_margin"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/phase1_description"
+            android:id="@+id/tvDesc"/>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:id="@+id/btnStart"
+            android:text="@string/start"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/verifier_buttons.xml b/apps/CtsVerifier/res/layout/verifier_buttons.xml
new file mode 100644
index 0000000..6a80316
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/verifier_buttons.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/llPassFail"
+              android:layout_alignParentTop="true"
+              android:background="@android:color/transparent"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+    <Button
+            android:id="@+id/btnPass"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:text="@string/pass"
+            android:enabled="false"
+            android:drawableTop="@drawable/fs_good"/>
+
+    <Button
+            android:id="@+id/btnInfo"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:text="@string/info"
+            android:drawableTop="@drawable/fs_indeterminate"/>
+
+    <Button
+            android:id="@+id/btnFail"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:text="@string/fail"
+            android:drawableTop="@drawable/fs_error"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/menu/menu_cts.xml b/apps/CtsVerifier/res/menu/menu_cts.xml
new file mode 100644
index 0000000..f6a51b1
--- /dev/null
+++ b/apps/CtsVerifier/res/menu/menu_cts.xml
@@ -0,0 +1,8 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:tools="http://schemas.android.com/tools"
+      tools:context=".Activities.TestActivity">
+    <item android:id="@+id/action_save_results" android:title="@string/save"
+          android:icon="@drawable/ic_save" android:showAsAction="ifRoom"/>
+    <item android:id="@+id/action_xml" android:title="@string/action_xml"
+          android:showAsAction="ifRoom"/>
+</menu>
diff --git a/apps/CtsVerifier/res/raw/cone_obj b/apps/CtsVerifier/res/raw/cone_obj
new file mode 100644
index 0000000..c95136a
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/cone_obj
@@ -0,0 +1,132 @@
+# Blender v2.76 (sub 0) OBJ File: 'cone.blend'
+# www.blender.org
+o Cone
+v 0.000000 -0.075000 0.125000
+v 0.000000 -0.000000 -0.125000
+v 0.014632 -0.073559 0.125000
+v 0.028701 -0.069291 0.125000
+v 0.041668 -0.062360 0.125000
+v 0.053033 -0.053033 0.125000
+v 0.062360 -0.041668 0.125000
+v 0.069291 -0.028701 0.125000
+v 0.073559 -0.014632 0.125000
+v 0.075000 -0.000000 0.125000
+v 0.073559 0.014632 0.125000
+v 0.069291 0.028701 0.125000
+v 0.062360 0.041668 0.125000
+v 0.053033 0.053033 0.125000
+v 0.041668 0.062360 0.125000
+v 0.028701 0.069291 0.125000
+v 0.014632 0.073559 0.125000
+v -0.000000 0.075000 0.125000
+v -0.014632 0.073559 0.125000
+v -0.028701 0.069291 0.125000
+v -0.041668 0.062360 0.125000
+v -0.053033 0.053033 0.125000
+v -0.062360 0.041668 0.125000
+v -0.069291 0.028701 0.125000
+v -0.073559 0.014632 0.125000
+v -0.075000 -0.000000 0.125000
+v -0.073559 -0.014632 0.125000
+v -0.069291 -0.028701 0.125000
+v -0.062360 -0.041668 0.125000
+v -0.053033 -0.053033 0.125000
+v -0.041668 -0.062360 0.125000
+v -0.028701 -0.069291 0.125000
+v -0.014632 -0.073559 0.125000
+vn -0.278200 -0.916900 -0.286100
+vn 0.093900 -0.953600 -0.286100
+vn -0.451700 -0.845100 -0.286100
+vn -0.607900 -0.740700 -0.286100
+vn -0.740700 -0.607900 -0.286100
+vn -0.845100 -0.451700 -0.286100
+vn -0.916900 -0.278200 -0.286100
+vn -0.953600 -0.093900 -0.286100
+vn -0.953600 0.093900 -0.286100
+vn -0.916900 0.278200 -0.286100
+vn -0.845100 0.451700 -0.286100
+vn -0.740700 0.607900 -0.286100
+vn -0.607900 0.740700 -0.286100
+vn -0.451700 0.845100 -0.286100
+vn -0.278200 0.916900 -0.286100
+vn -0.093900 0.953600 -0.286100
+vn 0.093900 0.953600 -0.286100
+vn 0.278200 0.916900 -0.286100
+vn 0.451700 0.845100 -0.286100
+vn 0.607900 0.740700 -0.286100
+vn 0.740700 0.607900 -0.286100
+vn 0.845100 0.451700 -0.286100
+vn 0.916900 0.278200 -0.286100
+vn 0.953600 0.093900 -0.286100
+vn 0.953600 -0.093900 -0.286100
+vn 0.916900 -0.278200 -0.286100
+vn 0.845100 -0.451700 -0.286100
+vn 0.740700 -0.607900 -0.286100
+vn 0.607900 -0.740700 -0.286100
+vn 0.451700 -0.845100 -0.286100
+vn -0.093900 -0.953600 -0.286100
+vn 0.278200 -0.916900 -0.286100
+vn 0.000000 0.000000 1.000000
+s off
+f 32//1 2//1 33//1
+f 1//2 2//2 3//2
+f 31//3 2//3 32//3
+f 30//4 2//4 31//4
+f 29//5 2//5 30//5
+f 28//6 2//6 29//6
+f 27//7 2//7 28//7
+f 26//8 2//8 27//8
+f 25//9 2//9 26//9
+f 24//10 2//10 25//10
+f 23//11 2//11 24//11
+f 22//12 2//12 23//12
+f 21//13 2//13 22//13
+f 20//14 2//14 21//14
+f 19//15 2//15 20//15
+f 18//16 2//16 19//16
+f 17//17 2//17 18//17
+f 16//18 2//18 17//18
+f 15//19 2//19 16//19
+f 14//20 2//20 15//20
+f 13//21 2//21 14//21
+f 12//22 2//22 13//22
+f 11//23 2//23 12//23
+f 10//24 2//24 11//24
+f 9//25 2//25 10//25
+f 8//26 2//26 9//26
+f 7//27 2//27 8//27
+f 6//28 2//28 7//28
+f 5//29 2//29 6//29
+f 4//30 2//30 5//30
+f 33//31 2//31 1//31
+f 3//32 2//32 4//32
+f 17//33 25//33 9//33
+f 33//33 1//33 3//33
+f 3//33 4//33 5//33
+f 5//33 6//33 7//33
+f 7//33 8//33 5//33
+f 9//33 10//33 13//33
+f 11//33 12//33 13//33
+f 13//33 14//33 15//33
+f 15//33 16//33 17//33
+f 17//33 18//33 19//33
+f 19//33 20//33 21//33
+f 21//33 22//33 23//33
+f 23//33 24//33 25//33
+f 25//33 26//33 27//33
+f 27//33 28//33 29//33
+f 29//33 30//33 31//33
+f 31//33 32//33 33//33
+f 33//33 3//33 9//33
+f 5//33 8//33 9//33
+f 10//33 11//33 13//33
+f 13//33 15//33 9//33
+f 17//33 19//33 25//33
+f 21//33 23//33 25//33
+f 25//33 27//33 33//33
+f 29//33 31//33 33//33
+f 3//33 5//33 9//33
+f 9//33 15//33 17//33
+f 19//33 21//33 25//33
+f 27//33 29//33 33//33
+f 33//33 9//33 25//33
diff --git a/apps/CtsVerifier/res/raw/ring_obj b/apps/CtsVerifier/res/raw/ring_obj
new file mode 100644
index 0000000..01b6e7c
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/ring_obj
@@ -0,0 +1,8144 @@
+# Blender v2.76 (sub 0) OBJ File: 'ring3.blend'
+# www.blender.org
+mtllib ring.mtl
+o Torus
+v 0.172500 0.000000 0.000000
+v 0.171733 -0.000000 0.005823
+v 0.169486 -0.000000 0.011250
+v 0.165910 -0.000000 0.015910
+v 0.161250 -0.000000 0.019486
+v 0.155823 -0.000000 0.021733
+v 0.150000 -0.000000 0.022500
+v 0.144177 -0.000000 0.021733
+v 0.138750 -0.000000 0.019486
+v 0.134090 -0.000000 0.015910
+v 0.130514 -0.000000 0.011250
+v 0.128267 -0.000000 0.005823
+v 0.127500 -0.000000 0.000000
+v 0.128267 0.000000 -0.005823
+v 0.130514 0.000000 -0.011250
+v 0.134090 0.000000 -0.015910
+v 0.138750 0.000000 -0.019486
+v 0.144177 0.000000 -0.021733
+v 0.150000 0.000000 -0.022500
+v 0.155823 0.000000 -0.021733
+v 0.161250 0.000000 -0.019486
+v 0.165910 0.000000 -0.015910
+v 0.169486 0.000000 -0.011250
+v 0.171733 0.000000 -0.005823
+v 0.172131 0.011282 0.000000
+v 0.171366 0.011232 0.005823
+v 0.169123 0.011085 0.011250
+v 0.165555 0.010851 0.015910
+v 0.160905 0.010546 0.019486
+v 0.155490 0.010191 0.021733
+v 0.149679 0.009810 0.022500
+v 0.143868 0.009430 0.021733
+v 0.138453 0.009075 0.019486
+v 0.133803 0.008770 0.015910
+v 0.130235 0.008536 0.011250
+v 0.127992 0.008389 0.005823
+v 0.127227 0.008339 0.000000
+v 0.127992 0.008389 -0.005823
+v 0.130235 0.008536 -0.011250
+v 0.133803 0.008770 -0.015910
+v 0.138453 0.009075 -0.019486
+v 0.143868 0.009430 -0.021733
+v 0.149679 0.009810 -0.022500
+v 0.155490 0.010191 -0.021733
+v 0.160905 0.010546 -0.019486
+v 0.165555 0.010851 -0.015910
+v 0.169123 0.011085 -0.011250
+v 0.171366 0.011232 -0.005823
+v 0.171024 0.022516 0.000000
+v 0.170264 0.022416 0.005823
+v 0.168036 0.022122 0.011250
+v 0.164491 0.021656 0.015910
+v 0.159871 0.021047 0.019486
+v 0.154490 0.020339 0.021733
+v 0.148717 0.019579 0.022500
+v 0.142943 0.018819 0.021733
+v 0.137563 0.018111 0.019486
+v 0.132943 0.017502 0.015910
+v 0.129398 0.017036 0.011250
+v 0.127169 0.016742 0.005823
+v 0.126409 0.016642 0.000000
+v 0.127169 0.016742 -0.005823
+v 0.129398 0.017036 -0.011250
+v 0.132943 0.017502 -0.015910
+v 0.137563 0.018111 -0.019486
+v 0.142943 0.018819 -0.021733
+v 0.148717 0.019579 -0.022500
+v 0.154490 0.020339 -0.021733
+v 0.159871 0.021047 -0.019486
+v 0.164491 0.021656 -0.015910
+v 0.168036 0.022122 -0.011250
+v 0.170264 0.022416 -0.005823
+v 0.169185 0.033653 0.000000
+v 0.168434 0.033504 0.005823
+v 0.166229 0.033065 0.011250
+v 0.162722 0.032367 0.015910
+v 0.158152 0.031458 0.019486
+v 0.152829 0.030400 0.021733
+v 0.147118 0.029264 0.022500
+v 0.141406 0.028127 0.021733
+v 0.136084 0.027069 0.019486
+v 0.131514 0.026160 0.015910
+v 0.128007 0.025462 0.011250
+v 0.125802 0.025024 0.005823
+v 0.125050 0.024874 0.000000
+v 0.125802 0.025024 -0.005823
+v 0.128007 0.025462 -0.011250
+v 0.131514 0.026160 -0.015910
+v 0.136084 0.027069 -0.019486
+v 0.141406 0.028127 -0.021733
+v 0.147118 0.029264 -0.022500
+v 0.152829 0.030400 -0.021733
+v 0.158152 0.031458 -0.019486
+v 0.162722 0.032367 -0.015910
+v 0.166229 0.033065 -0.011250
+v 0.168434 0.033504 -0.005823
+v 0.166622 0.044646 0.000000
+v 0.165882 0.044448 0.005823
+v 0.163711 0.043866 0.011250
+v 0.160257 0.042941 0.015910
+v 0.155756 0.041735 0.019486
+v 0.150514 0.040330 0.021733
+v 0.144889 0.038823 0.022500
+v 0.139264 0.037316 0.021733
+v 0.134022 0.035911 0.019486
+v 0.129521 0.034705 0.015910
+v 0.126067 0.033780 0.011250
+v 0.123896 0.033198 0.005823
+v 0.123156 0.032999 0.000000
+v 0.123896 0.033198 -0.005823
+v 0.126067 0.033780 -0.011250
+v 0.129521 0.034705 -0.015910
+v 0.134022 0.035911 -0.019486
+v 0.139264 0.037316 -0.021733
+v 0.144889 0.038823 -0.022500
+v 0.150514 0.040330 -0.021733
+v 0.155756 0.041735 -0.019486
+v 0.160257 0.042941 -0.015910
+v 0.163711 0.043866 -0.011250
+v 0.165882 0.044448 -0.005823
+v 0.163345 0.055448 0.000000
+v 0.162619 0.055202 0.005823
+v 0.160491 0.054479 0.011250
+v 0.157105 0.053330 0.015910
+v 0.152692 0.051832 0.019486
+v 0.147554 0.050088 0.021733
+v 0.142040 0.048216 0.022500
+v 0.136525 0.046344 0.021733
+v 0.131387 0.044600 0.019486
+v 0.126974 0.043102 0.015910
+v 0.123588 0.041952 0.011250
+v 0.121460 0.041230 0.005823
+v 0.120734 0.040984 0.000000
+v 0.121460 0.041230 -0.005823
+v 0.123588 0.041952 -0.011250
+v 0.126974 0.043102 -0.015910
+v 0.131387 0.044600 -0.019486
+v 0.136525 0.046344 -0.021733
+v 0.142040 0.048216 -0.022500
+v 0.147554 0.050088 -0.021733
+v 0.152692 0.051832 -0.019486
+v 0.157105 0.053330 -0.015910
+v 0.160491 0.054479 -0.011250
+v 0.162619 0.055202 -0.005823
+v 0.159369 0.066013 0.000000
+v 0.158661 0.065719 0.005823
+v 0.156584 0.064859 0.011250
+v 0.153281 0.063491 0.015910
+v 0.148976 0.061708 0.019486
+v 0.143962 0.059631 0.021733
+v 0.138582 0.057403 0.022500
+v 0.133202 0.055174 0.021733
+v 0.128188 0.053097 0.019486
+v 0.123883 0.051314 0.015910
+v 0.120580 0.049946 0.011250
+v 0.118503 0.049086 0.005823
+v 0.117795 0.048792 0.000000
+v 0.118503 0.049086 -0.005823
+v 0.120580 0.049946 -0.011250
+v 0.123883 0.051314 -0.015910
+v 0.128188 0.053097 -0.019486
+v 0.133202 0.055174 -0.021733
+v 0.138582 0.057403 -0.022500
+v 0.143962 0.059631 -0.021733
+v 0.148976 0.061708 -0.019486
+v 0.153281 0.063491 -0.015910
+v 0.156584 0.064859 -0.011250
+v 0.158661 0.065719 -0.005823
+v 0.154711 0.076295 0.000000
+v 0.154023 0.075956 0.005823
+v 0.152007 0.074962 0.011250
+v 0.148800 0.073380 0.015910
+v 0.144621 0.071319 0.019486
+v 0.139754 0.068919 0.021733
+v 0.134531 0.066343 0.022500
+v 0.129308 0.063768 0.021733
+v 0.124441 0.061368 0.019486
+v 0.120262 0.059307 0.015910
+v 0.117055 0.057725 0.011250
+v 0.115039 0.056731 0.005823
+v 0.114351 0.056392 0.000000
+v 0.115039 0.056731 -0.005823
+v 0.117055 0.057725 -0.011250
+v 0.120262 0.059307 -0.015910
+v 0.124441 0.061368 -0.019486
+v 0.129308 0.063768 -0.021733
+v 0.134531 0.066343 -0.022500
+v 0.139754 0.068919 -0.021733
+v 0.144621 0.071319 -0.019486
+v 0.148800 0.073380 -0.015910
+v 0.152007 0.074962 -0.011250
+v 0.154023 0.075956 -0.005823
+v 0.149389 0.086250 0.000000
+v 0.148725 0.085867 0.005823
+v 0.146779 0.084743 0.011250
+v 0.143682 0.082955 0.015910
+v 0.139647 0.080625 0.019486
+v 0.134947 0.077912 0.021733
+v 0.129904 0.075000 0.022500
+v 0.124861 0.072088 0.021733
+v 0.120161 0.069375 0.019486
+v 0.116125 0.067045 0.015910
+v 0.113029 0.065257 0.011250
+v 0.111082 0.064133 0.005823
+v 0.110418 0.063750 0.000000
+v 0.111082 0.064133 -0.005823
+v 0.113029 0.065257 -0.011250
+v 0.116125 0.067045 -0.015910
+v 0.120161 0.069375 -0.019486
+v 0.124861 0.072088 -0.021733
+v 0.129904 0.075000 -0.022500
+v 0.134947 0.077912 -0.021733
+v 0.139647 0.080625 -0.019486
+v 0.143682 0.082955 -0.015910
+v 0.146779 0.084743 -0.011250
+v 0.148725 0.085867 -0.005823
+v 0.143429 0.095836 0.000000
+v 0.142791 0.095410 0.005823
+v 0.140922 0.094161 0.011250
+v 0.137949 0.092175 0.015910
+v 0.134074 0.089586 0.019486
+v 0.129562 0.086571 0.021733
+v 0.124720 0.083336 0.022500
+v 0.119878 0.080100 0.021733
+v 0.115366 0.077085 0.019486
+v 0.111492 0.074496 0.015910
+v 0.108519 0.072510 0.011250
+v 0.106650 0.071261 0.005823
+v 0.106012 0.070835 0.000000
+v 0.106650 0.071261 -0.005823
+v 0.108519 0.072510 -0.011250
+v 0.111492 0.074496 -0.015910
+v 0.115366 0.077085 -0.019486
+v 0.119878 0.080100 -0.021733
+v 0.124720 0.083336 -0.022500
+v 0.129562 0.086571 -0.021733
+v 0.134074 0.089586 -0.019486
+v 0.137949 0.092175 -0.015910
+v 0.140922 0.094161 -0.011250
+v 0.142791 0.095410 -0.005823
+v 0.136853 0.105011 0.000000
+v 0.136245 0.104545 0.005823
+v 0.134462 0.103176 0.011250
+v 0.131625 0.101000 0.015910
+v 0.127928 0.098163 0.019486
+v 0.123623 0.094859 0.021733
+v 0.119003 0.091314 0.022500
+v 0.114383 0.087769 0.021733
+v 0.110078 0.084466 0.019486
+v 0.106381 0.081629 0.015910
+v 0.103544 0.079452 0.011250
+v 0.101761 0.078084 0.005823
+v 0.101153 0.077617 0.000000
+v 0.101761 0.078084 -0.005823
+v 0.103544 0.079452 -0.011250
+v 0.106381 0.081629 -0.015910
+v 0.110078 0.084466 -0.019486
+v 0.114383 0.087769 -0.021733
+v 0.119003 0.091314 -0.022500
+v 0.123623 0.094859 -0.021733
+v 0.127928 0.098163 -0.019486
+v 0.131625 0.101000 -0.015910
+v 0.134462 0.103176 -0.011250
+v 0.136245 0.104545 -0.005823
+v 0.129692 0.113737 0.000000
+v 0.129116 0.113232 0.005823
+v 0.127426 0.111750 0.011250
+v 0.124738 0.109392 0.015910
+v 0.121234 0.106320 0.019486
+v 0.117154 0.102742 0.021733
+v 0.112776 0.098902 0.022500
+v 0.108398 0.095062 0.021733
+v 0.104318 0.091484 0.019486
+v 0.100814 0.088412 0.015910
+v 0.098126 0.086054 0.011250
+v 0.096436 0.084572 0.005823
+v 0.095860 0.084067 0.000000
+v 0.096436 0.084572 -0.005823
+v 0.098126 0.086054 -0.011250
+v 0.100814 0.088412 -0.015910
+v 0.104318 0.091484 -0.019486
+v 0.108398 0.095062 -0.021733
+v 0.112776 0.098902 -0.022500
+v 0.117154 0.102742 -0.021733
+v 0.121234 0.106320 -0.019486
+v 0.124738 0.109392 -0.015910
+v 0.127426 0.111750 -0.011250
+v 0.129116 0.113232 -0.005823
+v 0.121976 0.121976 0.000000
+v 0.121434 0.121434 0.005823
+v 0.119844 0.119844 0.011250
+v 0.117316 0.117316 0.015910
+v 0.114021 0.114021 0.019486
+v 0.110184 0.110184 0.021733
+v 0.106066 0.106066 0.022500
+v 0.101948 0.101948 0.021733
+v 0.098111 0.098111 0.019486
+v 0.094816 0.094816 0.015910
+v 0.092288 0.092288 0.011250
+v 0.090698 0.090698 0.005823
+v 0.090156 0.090156 0.000000
+v 0.090698 0.090698 -0.005823
+v 0.092288 0.092288 -0.011250
+v 0.094816 0.094816 -0.015910
+v 0.098111 0.098111 -0.019486
+v 0.101948 0.101948 -0.021733
+v 0.106066 0.106066 -0.022500
+v 0.110184 0.110184 -0.021733
+v 0.114021 0.114021 -0.019486
+v 0.117316 0.117316 -0.015910
+v 0.119844 0.119844 -0.011250
+v 0.121434 0.121434 -0.005823
+v 0.113737 0.129692 0.000000
+v 0.113232 0.129116 0.005823
+v 0.111750 0.127426 0.011250
+v 0.109392 0.124738 0.015910
+v 0.106320 0.121234 0.019486
+v 0.102742 0.117154 0.021733
+v 0.098902 0.112776 0.022500
+v 0.095062 0.108398 0.021733
+v 0.091484 0.104318 0.019486
+v 0.088412 0.100814 0.015910
+v 0.086054 0.098126 0.011250
+v 0.084572 0.096436 0.005823
+v 0.084067 0.095860 0.000000
+v 0.084572 0.096436 -0.005823
+v 0.086054 0.098126 -0.011250
+v 0.088412 0.100814 -0.015910
+v 0.091484 0.104318 -0.019486
+v 0.095062 0.108398 -0.021733
+v 0.098902 0.112776 -0.022500
+v 0.102742 0.117154 -0.021733
+v 0.106320 0.121234 -0.019486
+v 0.109392 0.124738 -0.015910
+v 0.111750 0.127426 -0.011250
+v 0.113232 0.129116 -0.005823
+v 0.105011 0.136853 0.000000
+v 0.104545 0.136245 0.005823
+v 0.103176 0.134462 0.011250
+v 0.101000 0.131625 0.015910
+v 0.098163 0.127928 0.019486
+v 0.094859 0.123623 0.021733
+v 0.091314 0.119003 0.022500
+v 0.087769 0.114383 0.021733
+v 0.084466 0.110078 0.019486
+v 0.081629 0.106381 0.015910
+v 0.079452 0.103544 0.011250
+v 0.078084 0.101761 0.005823
+v 0.077617 0.101153 0.000000
+v 0.078084 0.101761 -0.005823
+v 0.079452 0.103544 -0.011250
+v 0.081629 0.106381 -0.015910
+v 0.084466 0.110078 -0.019486
+v 0.087769 0.114383 -0.021733
+v 0.091314 0.119003 -0.022500
+v 0.094859 0.123623 -0.021733
+v 0.098163 0.127928 -0.019486
+v 0.101000 0.131625 -0.015910
+v 0.103176 0.134462 -0.011250
+v 0.104545 0.136245 -0.005823
+v 0.095836 0.143429 0.000000
+v 0.095410 0.142791 0.005823
+v 0.094161 0.140922 0.011250
+v 0.092175 0.137949 0.015910
+v 0.089586 0.134074 0.019486
+v 0.086571 0.129562 0.021733
+v 0.083336 0.124720 0.022500
+v 0.080100 0.119878 0.021733
+v 0.077085 0.115366 0.019486
+v 0.074496 0.111492 0.015910
+v 0.072510 0.108519 0.011250
+v 0.071261 0.106650 0.005823
+v 0.070835 0.106012 0.000000
+v 0.071261 0.106650 -0.005823
+v 0.072510 0.108519 -0.011250
+v 0.074496 0.111492 -0.015910
+v 0.077085 0.115366 -0.019486
+v 0.080100 0.119878 -0.021733
+v 0.083336 0.124720 -0.022500
+v 0.086571 0.129562 -0.021733
+v 0.089586 0.134074 -0.019486
+v 0.092175 0.137949 -0.015910
+v 0.094161 0.140922 -0.011250
+v 0.095410 0.142791 -0.005823
+v 0.086250 0.149389 0.000000
+v 0.085867 0.148725 0.005823
+v 0.084743 0.146779 0.011250
+v 0.082955 0.143682 0.015910
+v 0.080625 0.139647 0.019486
+v 0.077912 0.134947 0.021733
+v 0.075000 0.129904 0.022500
+v 0.072088 0.124861 0.021733
+v 0.069375 0.120161 0.019486
+v 0.067045 0.116125 0.015910
+v 0.065257 0.113029 0.011250
+v 0.064133 0.111082 0.005823
+v 0.063750 0.110418 0.000000
+v 0.064133 0.111082 -0.005823
+v 0.065257 0.113029 -0.011250
+v 0.067045 0.116125 -0.015910
+v 0.069375 0.120161 -0.019486
+v 0.072088 0.124861 -0.021733
+v 0.075000 0.129904 -0.022500
+v 0.077912 0.134947 -0.021733
+v 0.080625 0.139647 -0.019486
+v 0.082955 0.143682 -0.015910
+v 0.084743 0.146779 -0.011250
+v 0.085867 0.148725 -0.005823
+v 0.076295 0.154711 0.000000
+v 0.075956 0.154023 0.005823
+v 0.074962 0.152007 0.011250
+v 0.073380 0.148800 0.015910
+v 0.071319 0.144621 0.019486
+v 0.068919 0.139754 0.021733
+v 0.066343 0.134531 0.022500
+v 0.063768 0.129308 0.021733
+v 0.061368 0.124441 0.019486
+v 0.059307 0.120262 0.015910
+v 0.057725 0.117055 0.011250
+v 0.056731 0.115039 0.005823
+v 0.056392 0.114351 0.000000
+v 0.056731 0.115039 -0.005823
+v 0.057725 0.117055 -0.011250
+v 0.059307 0.120262 -0.015910
+v 0.061368 0.124441 -0.019486
+v 0.063768 0.129308 -0.021733
+v 0.066343 0.134531 -0.022500
+v 0.068919 0.139754 -0.021733
+v 0.071319 0.144621 -0.019486
+v 0.073380 0.148800 -0.015910
+v 0.074962 0.152007 -0.011250
+v 0.075956 0.154023 -0.005823
+v 0.066013 0.159369 0.000000
+v 0.065720 0.158661 0.005823
+v 0.064859 0.156584 0.011250
+v 0.063491 0.153281 0.015910
+v 0.061708 0.148976 0.019486
+v 0.059631 0.143962 0.021733
+v 0.057403 0.138582 0.022500
+v 0.055174 0.133202 0.021733
+v 0.053097 0.128188 0.019486
+v 0.051314 0.123883 0.015910
+v 0.049946 0.120580 0.011250
+v 0.049086 0.118503 0.005823
+v 0.048792 0.117795 0.000000
+v 0.049086 0.118503 -0.005823
+v 0.049946 0.120580 -0.011250
+v 0.051314 0.123883 -0.015910
+v 0.053097 0.128188 -0.019486
+v 0.055174 0.133202 -0.021733
+v 0.057403 0.138582 -0.022500
+v 0.059631 0.143962 -0.021733
+v 0.061708 0.148976 -0.019486
+v 0.063491 0.153281 -0.015910
+v 0.064859 0.156584 -0.011250
+v 0.065720 0.158661 -0.005823
+v 0.055448 0.163345 0.000000
+v 0.055202 0.162619 0.005823
+v 0.054479 0.160491 0.011250
+v 0.053330 0.157105 0.015910
+v 0.051832 0.152692 0.019486
+v 0.050088 0.147554 0.021733
+v 0.048216 0.142040 0.022500
+v 0.046344 0.136525 0.021733
+v 0.044600 0.131387 0.019486
+v 0.043102 0.126974 0.015910
+v 0.041952 0.123588 0.011250
+v 0.041230 0.121460 0.005823
+v 0.040984 0.120734 0.000000
+v 0.041230 0.121460 -0.005823
+v 0.041952 0.123588 -0.011250
+v 0.043102 0.126974 -0.015910
+v 0.044600 0.131387 -0.019486
+v 0.046344 0.136525 -0.021733
+v 0.048216 0.142040 -0.022500
+v 0.050088 0.147554 -0.021733
+v 0.051832 0.152692 -0.019486
+v 0.053330 0.157105 -0.015910
+v 0.054479 0.160491 -0.011250
+v 0.055202 0.162619 -0.005823
+v 0.044646 0.166622 0.000000
+v 0.044448 0.165882 0.005823
+v 0.043866 0.163710 0.011250
+v 0.042941 0.160257 0.015910
+v 0.041735 0.155756 0.019486
+v 0.040330 0.150514 0.021733
+v 0.038823 0.144889 0.022500
+v 0.037316 0.139264 0.021733
+v 0.035911 0.134022 0.019486
+v 0.034705 0.129521 0.015910
+v 0.033780 0.126067 0.011250
+v 0.033198 0.123896 0.005823
+v 0.032999 0.123156 0.000000
+v 0.033198 0.123896 -0.005823
+v 0.033780 0.126067 -0.011250
+v 0.034705 0.129521 -0.015910
+v 0.035911 0.134022 -0.019486
+v 0.037316 0.139264 -0.021733
+v 0.038823 0.144889 -0.022500
+v 0.040330 0.150514 -0.021733
+v 0.041735 0.155756 -0.019486
+v 0.042941 0.160257 -0.015910
+v 0.043866 0.163710 -0.011250
+v 0.044448 0.165882 -0.005823
+v 0.033653 0.169185 0.000000
+v 0.033504 0.168434 0.005823
+v 0.033065 0.166229 0.011250
+v 0.032367 0.162722 0.015910
+v 0.031458 0.158152 0.019486
+v 0.030400 0.152829 0.021733
+v 0.029264 0.147118 0.022500
+v 0.028127 0.141406 0.021733
+v 0.027069 0.136084 0.019486
+v 0.026160 0.131514 0.015910
+v 0.025462 0.128007 0.011250
+v 0.025024 0.125802 0.005823
+v 0.024874 0.125050 0.000000
+v 0.025024 0.125802 -0.005823
+v 0.025462 0.128007 -0.011250
+v 0.026160 0.131514 -0.015910
+v 0.027069 0.136084 -0.019486
+v 0.028127 0.141406 -0.021733
+v 0.029264 0.147118 -0.022500
+v 0.030400 0.152829 -0.021733
+v 0.031458 0.158152 -0.019486
+v 0.032367 0.162722 -0.015910
+v 0.033065 0.166229 -0.011250
+v 0.033504 0.168434 -0.005823
+v 0.022516 0.171024 0.000000
+v 0.022416 0.170264 0.005823
+v 0.022122 0.168036 0.011250
+v 0.021656 0.164491 0.015910
+v 0.021047 0.159871 0.019486
+v 0.020339 0.154490 0.021733
+v 0.019579 0.148717 0.022500
+v 0.018819 0.142943 0.021733
+v 0.018110 0.137563 0.019486
+v 0.017502 0.132943 0.015910
+v 0.017036 0.129398 0.011250
+v 0.016742 0.127169 0.005823
+v 0.016642 0.126409 0.000000
+v 0.016742 0.127169 -0.005823
+v 0.017036 0.129398 -0.011250
+v 0.017502 0.132943 -0.015910
+v 0.018110 0.137563 -0.019486
+v 0.018819 0.142943 -0.021733
+v 0.019579 0.148717 -0.022500
+v 0.020339 0.154490 -0.021733
+v 0.021047 0.159871 -0.019486
+v 0.021656 0.164491 -0.015910
+v 0.022122 0.168036 -0.011250
+v 0.022416 0.170264 -0.005823
+v 0.011282 0.172131 0.000000
+v 0.011232 0.171366 0.005823
+v 0.011085 0.169123 0.011250
+v 0.010851 0.165555 0.015910
+v 0.010546 0.160905 0.019486
+v 0.010191 0.155490 0.021733
+v 0.009810 0.149679 0.022500
+v 0.009430 0.143868 0.021733
+v 0.009075 0.138453 0.019486
+v 0.008770 0.133803 0.015910
+v 0.008536 0.130235 0.011250
+v 0.008389 0.127992 0.005823
+v 0.008339 0.127227 0.000000
+v 0.008389 0.127992 -0.005823
+v 0.008536 0.130235 -0.011250
+v 0.008770 0.133803 -0.015910
+v 0.009075 0.138453 -0.019486
+v 0.009430 0.143868 -0.021733
+v 0.009810 0.149679 -0.022500
+v 0.010191 0.155490 -0.021733
+v 0.010546 0.160905 -0.019486
+v 0.010851 0.165555 -0.015910
+v 0.011085 0.169123 -0.011250
+v 0.011232 0.171366 -0.005823
+v 0.000000 0.172500 0.000000
+v 0.000000 0.171733 0.005823
+v 0.000000 0.169486 0.011250
+v 0.000000 0.165910 0.015910
+v 0.000000 0.161250 0.019486
+v 0.000000 0.155823 0.021733
+v 0.000000 0.150000 0.022500
+v 0.000000 0.144177 0.021733
+v 0.000000 0.138750 0.019486
+v 0.000000 0.134090 0.015910
+v 0.000000 0.130514 0.011250
+v 0.000000 0.128267 0.005823
+v 0.000000 0.127500 0.000000
+v 0.000000 0.128267 -0.005823
+v 0.000000 0.130514 -0.011250
+v 0.000000 0.134090 -0.015910
+v 0.000000 0.138750 -0.019486
+v 0.000000 0.144177 -0.021733
+v 0.000000 0.150000 -0.022500
+v 0.000000 0.155823 -0.021733
+v 0.000000 0.161250 -0.019486
+v 0.000000 0.165910 -0.015910
+v 0.000000 0.169486 -0.011250
+v 0.000000 0.171733 -0.005823
+v -0.011282 0.172131 0.000000
+v -0.011232 0.171366 0.005823
+v -0.011085 0.169123 0.011250
+v -0.010851 0.165555 0.015910
+v -0.010546 0.160905 0.019486
+v -0.010191 0.155490 0.021733
+v -0.009810 0.149679 0.022500
+v -0.009430 0.143868 0.021733
+v -0.009075 0.138453 0.019486
+v -0.008770 0.133803 0.015910
+v -0.008536 0.130235 0.011250
+v -0.008389 0.127992 0.005823
+v -0.008339 0.127227 0.000000
+v -0.008389 0.127992 -0.005823
+v -0.008536 0.130235 -0.011250
+v -0.008770 0.133803 -0.015910
+v -0.009075 0.138453 -0.019486
+v -0.009430 0.143868 -0.021733
+v -0.009810 0.149679 -0.022500
+v -0.010191 0.155490 -0.021733
+v -0.010546 0.160905 -0.019486
+v -0.010851 0.165555 -0.015910
+v -0.011085 0.169123 -0.011250
+v -0.011232 0.171366 -0.005823
+v -0.022516 0.171024 0.000000
+v -0.022416 0.170264 0.005823
+v -0.022122 0.168036 0.011250
+v -0.021656 0.164491 0.015910
+v -0.021047 0.159871 0.019486
+v -0.020339 0.154490 0.021733
+v -0.019579 0.148717 0.022500
+v -0.018819 0.142943 0.021733
+v -0.018111 0.137563 0.019486
+v -0.017502 0.132943 0.015910
+v -0.017036 0.129398 0.011250
+v -0.016742 0.127169 0.005823
+v -0.016642 0.126409 0.000000
+v -0.016742 0.127169 -0.005823
+v -0.017036 0.129398 -0.011250
+v -0.017502 0.132943 -0.015910
+v -0.018111 0.137563 -0.019486
+v -0.018819 0.142943 -0.021733
+v -0.019579 0.148717 -0.022500
+v -0.020339 0.154490 -0.021733
+v -0.021047 0.159871 -0.019486
+v -0.021656 0.164491 -0.015910
+v -0.022122 0.168036 -0.011250
+v -0.022416 0.170264 -0.005823
+v -0.033653 0.169185 0.000000
+v -0.033504 0.168434 0.005823
+v -0.033065 0.166229 0.011250
+v -0.032367 0.162722 0.015910
+v -0.031458 0.158152 0.019486
+v -0.030400 0.152829 0.021733
+v -0.029264 0.147118 0.022500
+v -0.028127 0.141406 0.021733
+v -0.027069 0.136084 0.019486
+v -0.026160 0.131514 0.015910
+v -0.025462 0.128007 0.011250
+v -0.025024 0.125802 0.005823
+v -0.024874 0.125050 0.000000
+v -0.025024 0.125802 -0.005823
+v -0.025462 0.128007 -0.011250
+v -0.026160 0.131514 -0.015910
+v -0.027069 0.136084 -0.019486
+v -0.028127 0.141406 -0.021733
+v -0.029264 0.147118 -0.022500
+v -0.030400 0.152829 -0.021733
+v -0.031458 0.158152 -0.019486
+v -0.032367 0.162722 -0.015910
+v -0.033065 0.166229 -0.011250
+v -0.033504 0.168434 -0.005823
+v -0.044646 0.166622 0.000000
+v -0.044448 0.165882 0.005823
+v -0.043866 0.163710 0.011250
+v -0.042941 0.160257 0.015910
+v -0.041735 0.155756 0.019486
+v -0.040330 0.150514 0.021733
+v -0.038823 0.144889 0.022500
+v -0.037316 0.139264 0.021733
+v -0.035911 0.134022 0.019486
+v -0.034705 0.129521 0.015910
+v -0.033780 0.126067 0.011250
+v -0.033198 0.123896 0.005823
+v -0.032999 0.123156 0.000000
+v -0.033198 0.123896 -0.005823
+v -0.033780 0.126067 -0.011250
+v -0.034705 0.129521 -0.015910
+v -0.035911 0.134022 -0.019486
+v -0.037316 0.139264 -0.021733
+v -0.038823 0.144889 -0.022500
+v -0.040330 0.150514 -0.021733
+v -0.041735 0.155756 -0.019486
+v -0.042941 0.160257 -0.015910
+v -0.043866 0.163710 -0.011250
+v -0.044448 0.165882 -0.005823
+v -0.055448 0.163345 0.000000
+v -0.055202 0.162619 0.005823
+v -0.054479 0.160491 0.011250
+v -0.053330 0.157105 0.015910
+v -0.051832 0.152692 0.019486
+v -0.050088 0.147554 0.021733
+v -0.048216 0.142040 0.022500
+v -0.046344 0.136525 0.021733
+v -0.044600 0.131387 0.019486
+v -0.043102 0.126974 0.015910
+v -0.041953 0.123588 0.011250
+v -0.041230 0.121460 0.005823
+v -0.040984 0.120734 0.000000
+v -0.041230 0.121460 -0.005823
+v -0.041953 0.123588 -0.011250
+v -0.043102 0.126974 -0.015910
+v -0.044600 0.131387 -0.019486
+v -0.046344 0.136525 -0.021733
+v -0.048216 0.142040 -0.022500
+v -0.050088 0.147554 -0.021733
+v -0.051832 0.152692 -0.019486
+v -0.053330 0.157105 -0.015910
+v -0.054479 0.160491 -0.011250
+v -0.055202 0.162619 -0.005823
+v -0.066013 0.159369 0.000000
+v -0.065720 0.158661 0.005823
+v -0.064859 0.156584 0.011250
+v -0.063491 0.153281 0.015910
+v -0.061708 0.148976 0.019486
+v -0.059631 0.143962 0.021733
+v -0.057403 0.138582 0.022500
+v -0.055174 0.133202 0.021733
+v -0.053097 0.128188 0.019486
+v -0.051314 0.123883 0.015910
+v -0.049946 0.120580 0.011250
+v -0.049086 0.118503 0.005823
+v -0.048792 0.117795 0.000000
+v -0.049086 0.118503 -0.005823
+v -0.049946 0.120580 -0.011250
+v -0.051314 0.123883 -0.015910
+v -0.053097 0.128188 -0.019486
+v -0.055174 0.133202 -0.021733
+v -0.057403 0.138582 -0.022500
+v -0.059631 0.143962 -0.021733
+v -0.061708 0.148976 -0.019486
+v -0.063491 0.153281 -0.015910
+v -0.064859 0.156584 -0.011250
+v -0.065720 0.158661 -0.005823
+v -0.076295 0.154711 0.000000
+v -0.075956 0.154023 0.005823
+v -0.074962 0.152007 0.011250
+v -0.073380 0.148800 0.015910
+v -0.071319 0.144621 0.019486
+v -0.068919 0.139754 0.021733
+v -0.066343 0.134531 0.022500
+v -0.063768 0.129308 0.021733
+v -0.061368 0.124441 0.019486
+v -0.059307 0.120262 0.015910
+v -0.057725 0.117055 0.011250
+v -0.056731 0.115039 0.005823
+v -0.056392 0.114351 0.000000
+v -0.056731 0.115039 -0.005823
+v -0.057725 0.117055 -0.011250
+v -0.059307 0.120262 -0.015910
+v -0.061368 0.124441 -0.019486
+v -0.063768 0.129308 -0.021733
+v -0.066343 0.134531 -0.022500
+v -0.068919 0.139754 -0.021733
+v -0.071319 0.144621 -0.019486
+v -0.073380 0.148800 -0.015910
+v -0.074962 0.152007 -0.011250
+v -0.075956 0.154023 -0.005823
+v -0.086250 0.149389 0.000000
+v -0.085867 0.148725 0.005823
+v -0.084743 0.146779 0.011250
+v -0.082955 0.143682 0.015910
+v -0.080625 0.139647 0.019486
+v -0.077912 0.134947 0.021733
+v -0.075000 0.129904 0.022500
+v -0.072088 0.124861 0.021733
+v -0.069375 0.120161 0.019486
+v -0.067045 0.116125 0.015910
+v -0.065257 0.113029 0.011250
+v -0.064133 0.111082 0.005823
+v -0.063750 0.110418 0.000000
+v -0.064133 0.111082 -0.005823
+v -0.065257 0.113029 -0.011250
+v -0.067045 0.116125 -0.015910
+v -0.069375 0.120161 -0.019486
+v -0.072088 0.124861 -0.021733
+v -0.075000 0.129904 -0.022500
+v -0.077912 0.134947 -0.021733
+v -0.080625 0.139647 -0.019486
+v -0.082955 0.143682 -0.015910
+v -0.084743 0.146779 -0.011250
+v -0.085867 0.148725 -0.005823
+v -0.095836 0.143429 0.000000
+v -0.095410 0.142791 0.005823
+v -0.094161 0.140922 0.011250
+v -0.092175 0.137949 0.015910
+v -0.089586 0.134075 0.019486
+v -0.086571 0.129562 0.021733
+v -0.083335 0.124720 0.022500
+v -0.080100 0.119878 0.021733
+v -0.077085 0.115366 0.019486
+v -0.074496 0.111492 0.015910
+v -0.072510 0.108519 0.011250
+v -0.071261 0.106650 0.005823
+v -0.070835 0.106012 0.000000
+v -0.071261 0.106650 -0.005823
+v -0.072510 0.108519 -0.011250
+v -0.074496 0.111492 -0.015910
+v -0.077085 0.115366 -0.019486
+v -0.080100 0.119878 -0.021733
+v -0.083335 0.124720 -0.022500
+v -0.086571 0.129562 -0.021733
+v -0.089586 0.134075 -0.019486
+v -0.092175 0.137949 -0.015910
+v -0.094161 0.140922 -0.011250
+v -0.095410 0.142791 -0.005823
+v -0.105011 0.136853 0.000000
+v -0.104545 0.136245 0.005823
+v -0.103176 0.134462 0.011250
+v -0.101000 0.131625 0.015910
+v -0.098163 0.127928 0.019486
+v -0.094859 0.123623 0.021733
+v -0.091314 0.119003 0.022500
+v -0.087769 0.114383 0.021733
+v -0.084466 0.110078 0.019486
+v -0.081629 0.106381 0.015910
+v -0.079452 0.103544 0.011250
+v -0.078084 0.101761 0.005823
+v -0.077617 0.101153 0.000000
+v -0.078084 0.101761 -0.005823
+v -0.079452 0.103544 -0.011250
+v -0.081629 0.106381 -0.015910
+v -0.084466 0.110078 -0.019486
+v -0.087769 0.114383 -0.021733
+v -0.091314 0.119003 -0.022500
+v -0.094859 0.123623 -0.021733
+v -0.098163 0.127928 -0.019486
+v -0.101000 0.131625 -0.015910
+v -0.103176 0.134462 -0.011250
+v -0.104545 0.136245 -0.005823
+v -0.113737 0.129692 0.000000
+v -0.113232 0.129116 0.005823
+v -0.111750 0.127426 0.011250
+v -0.109392 0.124738 0.015910
+v -0.106320 0.121234 0.019486
+v -0.102742 0.117154 0.021733
+v -0.098902 0.112776 0.022500
+v -0.095062 0.108398 0.021733
+v -0.091484 0.104318 0.019486
+v -0.088412 0.100814 0.015910
+v -0.086054 0.098126 0.011250
+v -0.084572 0.096436 0.005823
+v -0.084067 0.095860 0.000000
+v -0.084572 0.096436 -0.005823
+v -0.086054 0.098126 -0.011250
+v -0.088412 0.100814 -0.015910
+v -0.091484 0.104318 -0.019486
+v -0.095062 0.108398 -0.021733
+v -0.098902 0.112776 -0.022500
+v -0.102742 0.117154 -0.021733
+v -0.106320 0.121234 -0.019486
+v -0.109392 0.124738 -0.015910
+v -0.111750 0.127426 -0.011250
+v -0.113232 0.129116 -0.005823
+v -0.121976 0.121976 0.000000
+v -0.121434 0.121434 0.005823
+v -0.119844 0.119844 0.011250
+v -0.117316 0.117316 0.015910
+v -0.114021 0.114021 0.019486
+v -0.110184 0.110184 0.021733
+v -0.106066 0.106066 0.022500
+v -0.101948 0.101948 0.021733
+v -0.098111 0.098111 0.019486
+v -0.094816 0.094816 0.015910
+v -0.092288 0.092288 0.011250
+v -0.090698 0.090698 0.005823
+v -0.090156 0.090156 0.000000
+v -0.090698 0.090698 -0.005823
+v -0.092288 0.092288 -0.011250
+v -0.094816 0.094816 -0.015910
+v -0.098111 0.098111 -0.019486
+v -0.101948 0.101948 -0.021733
+v -0.106066 0.106066 -0.022500
+v -0.110184 0.110184 -0.021733
+v -0.114021 0.114021 -0.019486
+v -0.117316 0.117316 -0.015910
+v -0.119844 0.119844 -0.011250
+v -0.121434 0.121434 -0.005823
+v -0.129692 0.113737 0.000000
+v -0.129116 0.113232 0.005823
+v -0.127426 0.111750 0.011250
+v -0.124738 0.109392 0.015910
+v -0.121234 0.106320 0.019486
+v -0.117154 0.102742 0.021733
+v -0.112776 0.098902 0.022500
+v -0.108398 0.095062 0.021733
+v -0.104318 0.091484 0.019486
+v -0.100814 0.088412 0.015910
+v -0.098126 0.086054 0.011250
+v -0.096436 0.084572 0.005823
+v -0.095860 0.084067 0.000000
+v -0.096436 0.084572 -0.005823
+v -0.098126 0.086054 -0.011250
+v -0.100814 0.088412 -0.015910
+v -0.104318 0.091484 -0.019486
+v -0.108398 0.095062 -0.021733
+v -0.112776 0.098902 -0.022500
+v -0.117154 0.102742 -0.021733
+v -0.121234 0.106320 -0.019486
+v -0.124738 0.109392 -0.015910
+v -0.127426 0.111750 -0.011250
+v -0.129116 0.113232 -0.005823
+v -0.136853 0.105011 0.000000
+v -0.136245 0.104545 0.005823
+v -0.134462 0.103176 0.011250
+v -0.131625 0.101000 0.015910
+v -0.127928 0.098163 0.019486
+v -0.123623 0.094859 0.021733
+v -0.119003 0.091314 0.022500
+v -0.114383 0.087769 0.021733
+v -0.110078 0.084466 0.019486
+v -0.106381 0.081629 0.015910
+v -0.103544 0.079452 0.011250
+v -0.101761 0.078084 0.005823
+v -0.101153 0.077617 0.000000
+v -0.101761 0.078084 -0.005823
+v -0.103544 0.079452 -0.011250
+v -0.106381 0.081629 -0.015910
+v -0.110078 0.084466 -0.019486
+v -0.114383 0.087769 -0.021733
+v -0.119003 0.091314 -0.022500
+v -0.123623 0.094859 -0.021733
+v -0.127928 0.098163 -0.019486
+v -0.131625 0.101000 -0.015910
+v -0.134462 0.103176 -0.011250
+v -0.136245 0.104545 -0.005823
+v -0.143428 0.095836 0.000000
+v -0.142791 0.095410 0.005823
+v -0.140922 0.094161 0.011250
+v -0.137949 0.092175 0.015910
+v -0.134074 0.089586 0.019486
+v -0.129562 0.086571 0.021733
+v -0.124720 0.083336 0.022500
+v -0.119878 0.080100 0.021733
+v -0.115366 0.077085 0.019486
+v -0.111492 0.074496 0.015910
+v -0.108519 0.072510 0.011250
+v -0.106650 0.071261 0.005823
+v -0.106012 0.070835 0.000000
+v -0.106650 0.071261 -0.005823
+v -0.108519 0.072510 -0.011250
+v -0.111492 0.074496 -0.015910
+v -0.115366 0.077085 -0.019486
+v -0.119878 0.080100 -0.021733
+v -0.124720 0.083336 -0.022500
+v -0.129562 0.086571 -0.021733
+v -0.134074 0.089586 -0.019486
+v -0.137949 0.092175 -0.015910
+v -0.140922 0.094161 -0.011250
+v -0.142791 0.095410 -0.005823
+v -0.149389 0.086250 0.000000
+v -0.148725 0.085867 0.005823
+v -0.146779 0.084743 0.011250
+v -0.143682 0.082955 0.015910
+v -0.139647 0.080625 0.019486
+v -0.134947 0.077912 0.021733
+v -0.129904 0.075000 0.022500
+v -0.124861 0.072088 0.021733
+v -0.120161 0.069375 0.019486
+v -0.116125 0.067045 0.015910
+v -0.113029 0.065257 0.011250
+v -0.111082 0.064133 0.005823
+v -0.110418 0.063750 0.000000
+v -0.111082 0.064133 -0.005823
+v -0.113029 0.065257 -0.011250
+v -0.116125 0.067045 -0.015910
+v -0.120161 0.069375 -0.019486
+v -0.124861 0.072088 -0.021733
+v -0.129904 0.075000 -0.022500
+v -0.134947 0.077912 -0.021733
+v -0.139647 0.080625 -0.019486
+v -0.143682 0.082955 -0.015910
+v -0.146779 0.084743 -0.011250
+v -0.148725 0.085867 -0.005823
+v -0.154711 0.076295 0.000000
+v -0.154023 0.075956 0.005823
+v -0.152007 0.074962 0.011250
+v -0.148800 0.073380 0.015910
+v -0.144621 0.071319 0.019486
+v -0.139754 0.068919 0.021733
+v -0.134531 0.066343 0.022500
+v -0.129308 0.063768 0.021733
+v -0.124441 0.061368 0.019486
+v -0.120262 0.059307 0.015910
+v -0.117055 0.057725 0.011250
+v -0.115039 0.056731 0.005823
+v -0.114351 0.056392 0.000000
+v -0.115039 0.056731 -0.005823
+v -0.117055 0.057725 -0.011250
+v -0.120262 0.059307 -0.015910
+v -0.124441 0.061368 -0.019486
+v -0.129308 0.063768 -0.021733
+v -0.134531 0.066343 -0.022500
+v -0.139754 0.068919 -0.021733
+v -0.144621 0.071319 -0.019486
+v -0.148800 0.073380 -0.015910
+v -0.152007 0.074962 -0.011250
+v -0.154023 0.075956 -0.005823
+v -0.159369 0.066013 0.000000
+v -0.158661 0.065720 0.005823
+v -0.156584 0.064859 0.011250
+v -0.153281 0.063491 0.015910
+v -0.148976 0.061708 0.019486
+v -0.143962 0.059631 0.021733
+v -0.138582 0.057403 0.022500
+v -0.133202 0.055174 0.021733
+v -0.128188 0.053097 0.019486
+v -0.123883 0.051314 0.015910
+v -0.120580 0.049946 0.011250
+v -0.118503 0.049086 0.005823
+v -0.117795 0.048792 0.000000
+v -0.118503 0.049086 -0.005823
+v -0.120580 0.049946 -0.011250
+v -0.123883 0.051314 -0.015910
+v -0.128188 0.053097 -0.019486
+v -0.133202 0.055174 -0.021733
+v -0.138582 0.057403 -0.022500
+v -0.143962 0.059631 -0.021733
+v -0.148976 0.061708 -0.019486
+v -0.153281 0.063491 -0.015910
+v -0.156584 0.064859 -0.011250
+v -0.158661 0.065720 -0.005823
+v -0.163345 0.055448 0.000000
+v -0.162620 0.055202 0.005823
+v -0.160491 0.054479 0.011250
+v -0.157105 0.053330 0.015910
+v -0.152693 0.051832 0.019486
+v -0.147554 0.050088 0.021733
+v -0.142040 0.048216 0.022500
+v -0.136525 0.046344 0.021733
+v -0.131387 0.044600 0.019486
+v -0.126974 0.043102 0.015910
+v -0.123588 0.041952 0.011250
+v -0.121460 0.041230 0.005823
+v -0.120734 0.040984 0.000000
+v -0.121460 0.041230 -0.005823
+v -0.123588 0.041952 -0.011250
+v -0.126974 0.043102 -0.015910
+v -0.131387 0.044600 -0.019486
+v -0.136525 0.046344 -0.021733
+v -0.142040 0.048216 -0.022500
+v -0.147554 0.050088 -0.021733
+v -0.152693 0.051832 -0.019486
+v -0.157105 0.053330 -0.015910
+v -0.160491 0.054479 -0.011250
+v -0.162620 0.055202 -0.005823
+v -0.166622 0.044646 0.000000
+v -0.165882 0.044448 0.005823
+v -0.163711 0.043866 0.011250
+v -0.160257 0.042941 0.015910
+v -0.155756 0.041735 0.019486
+v -0.150514 0.040330 0.021733
+v -0.144889 0.038823 0.022500
+v -0.139264 0.037316 0.021733
+v -0.134022 0.035911 0.019486
+v -0.129521 0.034705 0.015910
+v -0.126067 0.033780 0.011250
+v -0.123896 0.033198 0.005823
+v -0.123156 0.032999 0.000000
+v -0.123896 0.033198 -0.005823
+v -0.126067 0.033780 -0.011250
+v -0.129521 0.034705 -0.015910
+v -0.134022 0.035911 -0.019486
+v -0.139264 0.037316 -0.021733
+v -0.144889 0.038823 -0.022500
+v -0.150514 0.040330 -0.021733
+v -0.155756 0.041735 -0.019486
+v -0.160257 0.042941 -0.015910
+v -0.163711 0.043866 -0.011250
+v -0.165882 0.044448 -0.005823
+v -0.169185 0.033653 0.000000
+v -0.168434 0.033504 0.005823
+v -0.166229 0.033065 0.011250
+v -0.162722 0.032367 0.015910
+v -0.158152 0.031458 0.019486
+v -0.152829 0.030400 0.021733
+v -0.147118 0.029264 0.022500
+v -0.141406 0.028127 0.021733
+v -0.136084 0.027069 0.019486
+v -0.131514 0.026160 0.015910
+v -0.128007 0.025462 0.011250
+v -0.125802 0.025024 0.005823
+v -0.125050 0.024874 0.000000
+v -0.125802 0.025024 -0.005823
+v -0.128007 0.025462 -0.011250
+v -0.131514 0.026160 -0.015910
+v -0.136084 0.027069 -0.019486
+v -0.141406 0.028127 -0.021733
+v -0.147118 0.029264 -0.022500
+v -0.152829 0.030400 -0.021733
+v -0.158152 0.031458 -0.019486
+v -0.162722 0.032367 -0.015910
+v -0.166229 0.033065 -0.011250
+v -0.168434 0.033504 -0.005823
+v -0.171024 0.022516 0.000000
+v -0.170264 0.022416 0.005823
+v -0.168036 0.022122 0.011250
+v -0.164491 0.021656 0.015910
+v -0.159871 0.021047 0.019486
+v -0.154490 0.020339 0.021733
+v -0.148717 0.019579 0.022500
+v -0.142943 0.018819 0.021733
+v -0.137563 0.018111 0.019486
+v -0.132943 0.017502 0.015910
+v -0.129398 0.017036 0.011250
+v -0.127169 0.016742 0.005823
+v -0.126409 0.016642 0.000000
+v -0.127169 0.016742 -0.005823
+v -0.129398 0.017036 -0.011250
+v -0.132943 0.017502 -0.015910
+v -0.137563 0.018111 -0.019486
+v -0.142943 0.018819 -0.021733
+v -0.148717 0.019579 -0.022500
+v -0.154490 0.020339 -0.021733
+v -0.159871 0.021047 -0.019486
+v -0.164491 0.021656 -0.015910
+v -0.168036 0.022122 -0.011250
+v -0.170264 0.022416 -0.005823
+v -0.172131 0.011282 0.000000
+v -0.171366 0.011232 0.005823
+v -0.169123 0.011085 0.011250
+v -0.165555 0.010851 0.015910
+v -0.160905 0.010546 0.019486
+v -0.155490 0.010191 0.021733
+v -0.149679 0.009811 0.022500
+v -0.143868 0.009430 0.021733
+v -0.138453 0.009075 0.019486
+v -0.133803 0.008770 0.015910
+v -0.130235 0.008536 0.011250
+v -0.127992 0.008389 0.005823
+v -0.127227 0.008339 0.000000
+v -0.127992 0.008389 -0.005823
+v -0.130235 0.008536 -0.011250
+v -0.133803 0.008770 -0.015910
+v -0.138453 0.009075 -0.019486
+v -0.143868 0.009430 -0.021733
+v -0.149679 0.009811 -0.022500
+v -0.155490 0.010191 -0.021733
+v -0.160905 0.010546 -0.019486
+v -0.165555 0.010851 -0.015910
+v -0.169123 0.011085 -0.011250
+v -0.171366 0.011232 -0.005823
+v -0.172500 0.000000 0.000000
+v -0.171733 0.000000 0.005823
+v -0.169486 0.000000 0.011250
+v -0.165910 0.000000 0.015910
+v -0.161250 0.000000 0.019486
+v -0.155823 0.000000 0.021733
+v -0.150000 0.000000 0.022500
+v -0.144177 0.000000 0.021733
+v -0.138750 0.000000 0.019486
+v -0.134090 0.000000 0.015910
+v -0.130514 0.000000 0.011250
+v -0.128267 0.000000 0.005823
+v -0.127500 0.000000 0.000000
+v -0.128267 0.000000 -0.005823
+v -0.130514 0.000000 -0.011250
+v -0.134090 0.000000 -0.015910
+v -0.138750 0.000000 -0.019486
+v -0.144177 0.000000 -0.021733
+v -0.150000 0.000000 -0.022500
+v -0.155823 0.000000 -0.021733
+v -0.161250 0.000000 -0.019486
+v -0.165910 0.000000 -0.015910
+v -0.169486 0.000000 -0.011250
+v -0.171733 0.000000 -0.005823
+v -0.172131 -0.011282 -0.000000
+v -0.171366 -0.011232 0.005823
+v -0.169123 -0.011085 0.011250
+v -0.165555 -0.010851 0.015910
+v -0.160905 -0.010546 0.019486
+v -0.155490 -0.010191 0.021733
+v -0.149679 -0.009810 0.022500
+v -0.143868 -0.009430 0.021733
+v -0.138453 -0.009075 0.019486
+v -0.133803 -0.008770 0.015910
+v -0.130235 -0.008536 0.011250
+v -0.127992 -0.008389 0.005823
+v -0.127227 -0.008339 -0.000000
+v -0.127992 -0.008389 -0.005823
+v -0.130235 -0.008536 -0.011250
+v -0.133803 -0.008770 -0.015910
+v -0.138453 -0.009075 -0.019486
+v -0.143868 -0.009430 -0.021733
+v -0.149679 -0.009810 -0.022500
+v -0.155490 -0.010191 -0.021733
+v -0.160905 -0.010546 -0.019486
+v -0.165555 -0.010851 -0.015910
+v -0.169123 -0.011085 -0.011250
+v -0.171366 -0.011232 -0.005823
+v -0.171024 -0.022516 -0.000000
+v -0.170264 -0.022416 0.005823
+v -0.168036 -0.022122 0.011250
+v -0.164491 -0.021656 0.015910
+v -0.159871 -0.021047 0.019486
+v -0.154490 -0.020339 0.021733
+v -0.148717 -0.019579 0.022500
+v -0.142943 -0.018819 0.021733
+v -0.137563 -0.018111 0.019486
+v -0.132943 -0.017502 0.015910
+v -0.129398 -0.017036 0.011250
+v -0.127169 -0.016742 0.005823
+v -0.126409 -0.016642 -0.000000
+v -0.127169 -0.016742 -0.005823
+v -0.129398 -0.017036 -0.011250
+v -0.132943 -0.017502 -0.015910
+v -0.137563 -0.018111 -0.019486
+v -0.142943 -0.018819 -0.021733
+v -0.148717 -0.019579 -0.022500
+v -0.154490 -0.020339 -0.021733
+v -0.159871 -0.021047 -0.019486
+v -0.164491 -0.021656 -0.015910
+v -0.168036 -0.022122 -0.011250
+v -0.170264 -0.022416 -0.005823
+v -0.169185 -0.033653 -0.000000
+v -0.168434 -0.033504 0.005823
+v -0.166229 -0.033065 0.011250
+v -0.162722 -0.032367 0.015910
+v -0.158152 -0.031458 0.019486
+v -0.152829 -0.030400 0.021733
+v -0.147118 -0.029264 0.022500
+v -0.141406 -0.028127 0.021733
+v -0.136084 -0.027069 0.019486
+v -0.131514 -0.026160 0.015910
+v -0.128007 -0.025462 0.011250
+v -0.125802 -0.025024 0.005823
+v -0.125050 -0.024874 -0.000000
+v -0.125802 -0.025024 -0.005823
+v -0.128007 -0.025462 -0.011250
+v -0.131514 -0.026160 -0.015910
+v -0.136084 -0.027069 -0.019486
+v -0.141406 -0.028127 -0.021733
+v -0.147118 -0.029264 -0.022500
+v -0.152829 -0.030400 -0.021733
+v -0.158152 -0.031458 -0.019486
+v -0.162722 -0.032367 -0.015910
+v -0.166229 -0.033065 -0.011250
+v -0.168434 -0.033504 -0.005823
+v -0.166622 -0.044646 -0.000000
+v -0.165882 -0.044448 0.005823
+v -0.163711 -0.043866 0.011250
+v -0.160257 -0.042941 0.015910
+v -0.155756 -0.041735 0.019486
+v -0.150514 -0.040330 0.021733
+v -0.144889 -0.038823 0.022500
+v -0.139264 -0.037316 0.021733
+v -0.134022 -0.035911 0.019486
+v -0.129521 -0.034705 0.015910
+v -0.126067 -0.033780 0.011250
+v -0.123896 -0.033198 0.005823
+v -0.123156 -0.032999 -0.000000
+v -0.123896 -0.033198 -0.005823
+v -0.126067 -0.033780 -0.011250
+v -0.129521 -0.034705 -0.015910
+v -0.134022 -0.035911 -0.019486
+v -0.139264 -0.037316 -0.021733
+v -0.144889 -0.038823 -0.022500
+v -0.150514 -0.040330 -0.021733
+v -0.155756 -0.041735 -0.019486
+v -0.160257 -0.042941 -0.015910
+v -0.163711 -0.043866 -0.011250
+v -0.165882 -0.044448 -0.005823
+v -0.163345 -0.055448 -0.000000
+v -0.162620 -0.055202 0.005823
+v -0.160491 -0.054479 0.011250
+v -0.157105 -0.053330 0.015910
+v -0.152693 -0.051832 0.019486
+v -0.147554 -0.050088 0.021733
+v -0.142040 -0.048216 0.022500
+v -0.136525 -0.046344 0.021733
+v -0.131387 -0.044600 0.019486
+v -0.126974 -0.043102 0.015910
+v -0.123588 -0.041952 0.011250
+v -0.121460 -0.041230 0.005823
+v -0.120734 -0.040984 -0.000000
+v -0.121460 -0.041230 -0.005823
+v -0.123588 -0.041952 -0.011250
+v -0.126974 -0.043102 -0.015910
+v -0.131387 -0.044600 -0.019486
+v -0.136525 -0.046344 -0.021733
+v -0.142040 -0.048216 -0.022500
+v -0.147554 -0.050088 -0.021733
+v -0.152693 -0.051832 -0.019486
+v -0.157105 -0.053330 -0.015910
+v -0.160491 -0.054479 -0.011250
+v -0.162620 -0.055202 -0.005823
+v -0.159369 -0.066013 -0.000000
+v -0.158661 -0.065719 0.005823
+v -0.156584 -0.064859 0.011250
+v -0.153281 -0.063491 0.015910
+v -0.148976 -0.061708 0.019486
+v -0.143962 -0.059631 0.021733
+v -0.138582 -0.057402 0.022500
+v -0.133202 -0.055174 0.021733
+v -0.128188 -0.053097 0.019486
+v -0.123883 -0.051314 0.015910
+v -0.120580 -0.049946 0.011250
+v -0.118503 -0.049085 0.005823
+v -0.117795 -0.048792 -0.000000
+v -0.118503 -0.049085 -0.005823
+v -0.120580 -0.049946 -0.011250
+v -0.123883 -0.051314 -0.015910
+v -0.128188 -0.053097 -0.019486
+v -0.133202 -0.055174 -0.021733
+v -0.138582 -0.057402 -0.022500
+v -0.143962 -0.059631 -0.021733
+v -0.148976 -0.061708 -0.019486
+v -0.153281 -0.063491 -0.015910
+v -0.156584 -0.064859 -0.011250
+v -0.158661 -0.065719 -0.005823
+v -0.154711 -0.076295 -0.000000
+v -0.154023 -0.075956 0.005823
+v -0.152007 -0.074962 0.011250
+v -0.148800 -0.073380 0.015910
+v -0.144621 -0.071319 0.019486
+v -0.139754 -0.068919 0.021733
+v -0.134531 -0.066343 0.022500
+v -0.129308 -0.063768 0.021733
+v -0.124441 -0.061368 0.019486
+v -0.120262 -0.059307 0.015910
+v -0.117055 -0.057725 0.011250
+v -0.115039 -0.056731 0.005823
+v -0.114351 -0.056392 -0.000000
+v -0.115039 -0.056731 -0.005823
+v -0.117055 -0.057725 -0.011250
+v -0.120262 -0.059307 -0.015910
+v -0.124441 -0.061368 -0.019486
+v -0.129308 -0.063768 -0.021733
+v -0.134531 -0.066343 -0.022500
+v -0.139754 -0.068919 -0.021733
+v -0.144621 -0.071319 -0.019486
+v -0.148800 -0.073380 -0.015910
+v -0.152007 -0.074962 -0.011250
+v -0.154023 -0.075956 -0.005823
+v -0.149389 -0.086250 -0.000000
+v -0.148725 -0.085867 0.005823
+v -0.146779 -0.084743 0.011250
+v -0.143682 -0.082955 0.015910
+v -0.139647 -0.080625 0.019486
+v -0.134947 -0.077912 0.021733
+v -0.129904 -0.075000 0.022500
+v -0.124861 -0.072088 0.021733
+v -0.120161 -0.069375 0.019486
+v -0.116125 -0.067045 0.015910
+v -0.113029 -0.065257 0.011250
+v -0.111082 -0.064133 0.005823
+v -0.110418 -0.063750 -0.000000
+v -0.111082 -0.064133 -0.005823
+v -0.113029 -0.065257 -0.011250
+v -0.116125 -0.067045 -0.015910
+v -0.120161 -0.069375 -0.019486
+v -0.124861 -0.072088 -0.021733
+v -0.129904 -0.075000 -0.022500
+v -0.134947 -0.077912 -0.021733
+v -0.139647 -0.080625 -0.019486
+v -0.143682 -0.082955 -0.015910
+v -0.146779 -0.084743 -0.011250
+v -0.148725 -0.085867 -0.005823
+v -0.143428 -0.095836 -0.000000
+v -0.142791 -0.095410 0.005823
+v -0.140922 -0.094161 0.011250
+v -0.137949 -0.092175 0.015910
+v -0.134074 -0.089586 0.019486
+v -0.129562 -0.086571 0.021733
+v -0.124720 -0.083336 0.022500
+v -0.119878 -0.080100 0.021733
+v -0.115366 -0.077085 0.019486
+v -0.111492 -0.074496 0.015910
+v -0.108519 -0.072510 0.011250
+v -0.106650 -0.071261 0.005823
+v -0.106012 -0.070835 -0.000000
+v -0.106650 -0.071261 -0.005823
+v -0.108519 -0.072510 -0.011250
+v -0.111492 -0.074496 -0.015910
+v -0.115366 -0.077085 -0.019486
+v -0.119878 -0.080100 -0.021733
+v -0.124720 -0.083336 -0.022500
+v -0.129562 -0.086571 -0.021733
+v -0.134074 -0.089586 -0.019486
+v -0.137949 -0.092175 -0.015910
+v -0.140922 -0.094161 -0.011250
+v -0.142791 -0.095410 -0.005823
+v -0.136853 -0.105011 -0.000000
+v -0.136245 -0.104545 0.005823
+v -0.134462 -0.103176 0.011250
+v -0.131625 -0.101000 0.015910
+v -0.127928 -0.098163 0.019486
+v -0.123623 -0.094859 0.021733
+v -0.119003 -0.091314 0.022500
+v -0.114383 -0.087769 0.021733
+v -0.110078 -0.084466 0.019486
+v -0.106381 -0.081629 0.015910
+v -0.103544 -0.079452 0.011250
+v -0.101761 -0.078084 0.005823
+v -0.101153 -0.077617 -0.000000
+v -0.101761 -0.078084 -0.005823
+v -0.103544 -0.079452 -0.011250
+v -0.106381 -0.081629 -0.015910
+v -0.110078 -0.084466 -0.019486
+v -0.114383 -0.087769 -0.021733
+v -0.119003 -0.091314 -0.022500
+v -0.123623 -0.094859 -0.021733
+v -0.127928 -0.098163 -0.019486
+v -0.131625 -0.101000 -0.015910
+v -0.134462 -0.103176 -0.011250
+v -0.136245 -0.104545 -0.005823
+v -0.129692 -0.113737 -0.000000
+v -0.129116 -0.113232 0.005823
+v -0.127426 -0.111750 0.011250
+v -0.124738 -0.109392 0.015910
+v -0.121234 -0.106320 0.019486
+v -0.117154 -0.102742 0.021733
+v -0.112776 -0.098902 0.022500
+v -0.108398 -0.095062 0.021733
+v -0.104318 -0.091484 0.019486
+v -0.100814 -0.088412 0.015910
+v -0.098126 -0.086054 0.011250
+v -0.096436 -0.084572 0.005823
+v -0.095860 -0.084067 -0.000000
+v -0.096436 -0.084572 -0.005823
+v -0.098126 -0.086054 -0.011250
+v -0.100814 -0.088412 -0.015910
+v -0.104318 -0.091484 -0.019486
+v -0.108398 -0.095062 -0.021733
+v -0.112776 -0.098902 -0.022500
+v -0.117154 -0.102742 -0.021733
+v -0.121234 -0.106320 -0.019486
+v -0.124738 -0.109392 -0.015910
+v -0.127426 -0.111750 -0.011250
+v -0.129116 -0.113232 -0.005823
+v -0.121976 -0.121976 -0.000000
+v -0.121434 -0.121434 0.005823
+v -0.119844 -0.119844 0.011250
+v -0.117316 -0.117316 0.015910
+v -0.114021 -0.114021 0.019486
+v -0.110184 -0.110184 0.021733
+v -0.106066 -0.106066 0.022500
+v -0.101948 -0.101948 0.021733
+v -0.098111 -0.098111 0.019486
+v -0.094816 -0.094816 0.015910
+v -0.092288 -0.092288 0.011250
+v -0.090698 -0.090698 0.005823
+v -0.090156 -0.090156 -0.000000
+v -0.090698 -0.090698 -0.005823
+v -0.092288 -0.092288 -0.011250
+v -0.094816 -0.094816 -0.015910
+v -0.098111 -0.098111 -0.019486
+v -0.101948 -0.101948 -0.021733
+v -0.106066 -0.106066 -0.022500
+v -0.110184 -0.110184 -0.021733
+v -0.114021 -0.114021 -0.019486
+v -0.117316 -0.117316 -0.015910
+v -0.119844 -0.119844 -0.011250
+v -0.121434 -0.121434 -0.005823
+v -0.113737 -0.129692 -0.000000
+v -0.113232 -0.129116 0.005823
+v -0.111750 -0.127426 0.011250
+v -0.109392 -0.124738 0.015910
+v -0.106320 -0.121234 0.019486
+v -0.102742 -0.117154 0.021733
+v -0.098902 -0.112776 0.022500
+v -0.095062 -0.108398 0.021733
+v -0.091484 -0.104318 0.019486
+v -0.088412 -0.100814 0.015910
+v -0.086054 -0.098126 0.011250
+v -0.084572 -0.096436 0.005823
+v -0.084067 -0.095860 -0.000000
+v -0.084572 -0.096436 -0.005823
+v -0.086054 -0.098126 -0.011250
+v -0.088412 -0.100814 -0.015910
+v -0.091484 -0.104318 -0.019486
+v -0.095062 -0.108398 -0.021733
+v -0.098902 -0.112776 -0.022500
+v -0.102742 -0.117154 -0.021733
+v -0.106320 -0.121234 -0.019486
+v -0.109392 -0.124738 -0.015910
+v -0.111750 -0.127426 -0.011250
+v -0.113232 -0.129116 -0.005823
+v -0.105011 -0.136853 -0.000000
+v -0.104545 -0.136245 0.005823
+v -0.103176 -0.134462 0.011250
+v -0.101000 -0.131625 0.015910
+v -0.098163 -0.127928 0.019486
+v -0.094859 -0.123623 0.021733
+v -0.091314 -0.119003 0.022500
+v -0.087769 -0.114383 0.021733
+v -0.084466 -0.110078 0.019486
+v -0.081629 -0.106381 0.015910
+v -0.079452 -0.103544 0.011250
+v -0.078084 -0.101761 0.005823
+v -0.077617 -0.101153 -0.000000
+v -0.078084 -0.101761 -0.005823
+v -0.079452 -0.103544 -0.011250
+v -0.081629 -0.106381 -0.015910
+v -0.084466 -0.110078 -0.019486
+v -0.087769 -0.114383 -0.021733
+v -0.091314 -0.119003 -0.022500
+v -0.094859 -0.123623 -0.021733
+v -0.098163 -0.127928 -0.019486
+v -0.101000 -0.131625 -0.015910
+v -0.103176 -0.134462 -0.011250
+v -0.104545 -0.136245 -0.005823
+v -0.095836 -0.143428 -0.000000
+v -0.095410 -0.142791 0.005823
+v -0.094161 -0.140922 0.011250
+v -0.092175 -0.137949 0.015910
+v -0.089586 -0.134074 0.019486
+v -0.086571 -0.129562 0.021733
+v -0.083336 -0.124720 0.022500
+v -0.080100 -0.119878 0.021733
+v -0.077085 -0.115366 0.019486
+v -0.074497 -0.111492 0.015910
+v -0.072510 -0.108519 0.011250
+v -0.071261 -0.106650 0.005823
+v -0.070835 -0.106012 -0.000000
+v -0.071261 -0.106650 -0.005823
+v -0.072510 -0.108519 -0.011250
+v -0.074497 -0.111492 -0.015910
+v -0.077085 -0.115366 -0.019486
+v -0.080100 -0.119878 -0.021733
+v -0.083336 -0.124720 -0.022500
+v -0.086571 -0.129562 -0.021733
+v -0.089586 -0.134074 -0.019486
+v -0.092175 -0.137949 -0.015910
+v -0.094161 -0.140922 -0.011250
+v -0.095410 -0.142791 -0.005823
+v -0.086250 -0.149389 -0.000000
+v -0.085867 -0.148725 0.005823
+v -0.084743 -0.146779 0.011250
+v -0.082955 -0.143682 0.015910
+v -0.080625 -0.139647 0.019486
+v -0.077912 -0.134947 0.021733
+v -0.075000 -0.129904 0.022500
+v -0.072088 -0.124861 0.021733
+v -0.069375 -0.120161 0.019486
+v -0.067045 -0.116125 0.015910
+v -0.065257 -0.113029 0.011250
+v -0.064133 -0.111082 0.005823
+v -0.063750 -0.110418 -0.000000
+v -0.064133 -0.111082 -0.005823
+v -0.065257 -0.113029 -0.011250
+v -0.067045 -0.116125 -0.015910
+v -0.069375 -0.120161 -0.019486
+v -0.072088 -0.124861 -0.021733
+v -0.075000 -0.129904 -0.022500
+v -0.077912 -0.134947 -0.021733
+v -0.080625 -0.139647 -0.019486
+v -0.082955 -0.143682 -0.015910
+v -0.084743 -0.146779 -0.011250
+v -0.085867 -0.148725 -0.005823
+v -0.076295 -0.154711 -0.000000
+v -0.075956 -0.154023 0.005823
+v -0.074962 -0.152007 0.011250
+v -0.073380 -0.148800 0.015910
+v -0.071319 -0.144621 0.019486
+v -0.068919 -0.139754 0.021733
+v -0.066343 -0.134531 0.022500
+v -0.063768 -0.129308 0.021733
+v -0.061368 -0.124441 0.019486
+v -0.059307 -0.120262 0.015910
+v -0.057725 -0.117055 0.011250
+v -0.056731 -0.115039 0.005823
+v -0.056392 -0.114351 -0.000000
+v -0.056731 -0.115039 -0.005823
+v -0.057725 -0.117055 -0.011250
+v -0.059307 -0.120262 -0.015910
+v -0.061368 -0.124441 -0.019486
+v -0.063768 -0.129308 -0.021733
+v -0.066343 -0.134531 -0.022500
+v -0.068919 -0.139754 -0.021733
+v -0.071319 -0.144621 -0.019486
+v -0.073380 -0.148800 -0.015910
+v -0.074962 -0.152007 -0.011250
+v -0.075956 -0.154023 -0.005823
+v -0.066013 -0.159369 -0.000000
+v -0.065720 -0.158661 0.005823
+v -0.064859 -0.156584 0.011250
+v -0.063491 -0.153281 0.015910
+v -0.061708 -0.148976 0.019486
+v -0.059631 -0.143962 0.021733
+v -0.057403 -0.138582 0.022500
+v -0.055174 -0.133202 0.021733
+v -0.053097 -0.128188 0.019486
+v -0.051314 -0.123883 0.015910
+v -0.049946 -0.120580 0.011250
+v -0.049086 -0.118503 0.005823
+v -0.048792 -0.117795 -0.000000
+v -0.049086 -0.118503 -0.005823
+v -0.049946 -0.120580 -0.011250
+v -0.051314 -0.123883 -0.015910
+v -0.053097 -0.128188 -0.019486
+v -0.055174 -0.133202 -0.021733
+v -0.057403 -0.138582 -0.022500
+v -0.059631 -0.143962 -0.021733
+v -0.061708 -0.148976 -0.019486
+v -0.063491 -0.153281 -0.015910
+v -0.064859 -0.156584 -0.011250
+v -0.065720 -0.158661 -0.005823
+v -0.055448 -0.163345 -0.000000
+v -0.055202 -0.162619 0.005823
+v -0.054479 -0.160491 0.011250
+v -0.053330 -0.157105 0.015910
+v -0.051832 -0.152692 0.019486
+v -0.050088 -0.147554 0.021733
+v -0.048216 -0.142040 0.022500
+v -0.046344 -0.136525 0.021733
+v -0.044600 -0.131387 0.019486
+v -0.043102 -0.126974 0.015910
+v -0.041953 -0.123588 0.011250
+v -0.041230 -0.121460 0.005823
+v -0.040984 -0.120734 -0.000000
+v -0.041230 -0.121460 -0.005823
+v -0.041953 -0.123588 -0.011250
+v -0.043102 -0.126974 -0.015910
+v -0.044600 -0.131387 -0.019486
+v -0.046344 -0.136525 -0.021733
+v -0.048216 -0.142040 -0.022500
+v -0.050088 -0.147554 -0.021733
+v -0.051832 -0.152692 -0.019486
+v -0.053330 -0.157105 -0.015910
+v -0.054479 -0.160491 -0.011250
+v -0.055202 -0.162619 -0.005823
+v -0.044646 -0.166622 -0.000000
+v -0.044448 -0.165882 0.005823
+v -0.043866 -0.163710 0.011250
+v -0.042941 -0.160257 0.015910
+v -0.041735 -0.155756 0.019486
+v -0.040330 -0.150514 0.021733
+v -0.038823 -0.144889 0.022500
+v -0.037316 -0.139264 0.021733
+v -0.035911 -0.134022 0.019486
+v -0.034705 -0.129521 0.015910
+v -0.033780 -0.126067 0.011250
+v -0.033198 -0.123896 0.005823
+v -0.032999 -0.123156 -0.000000
+v -0.033198 -0.123896 -0.005823
+v -0.033780 -0.126067 -0.011250
+v -0.034705 -0.129521 -0.015910
+v -0.035911 -0.134022 -0.019486
+v -0.037316 -0.139264 -0.021733
+v -0.038823 -0.144889 -0.022500
+v -0.040330 -0.150514 -0.021733
+v -0.041735 -0.155756 -0.019486
+v -0.042941 -0.160257 -0.015910
+v -0.043866 -0.163710 -0.011250
+v -0.044448 -0.165882 -0.005823
+v -0.033653 -0.169185 -0.000000
+v -0.033504 -0.168434 0.005823
+v -0.033065 -0.166229 0.011250
+v -0.032367 -0.162722 0.015910
+v -0.031458 -0.158152 0.019486
+v -0.030400 -0.152829 0.021733
+v -0.029264 -0.147118 0.022500
+v -0.028128 -0.141406 0.021733
+v -0.027069 -0.136084 0.019486
+v -0.026160 -0.131514 0.015910
+v -0.025462 -0.128007 0.011250
+v -0.025024 -0.125802 0.005823
+v -0.024874 -0.125050 -0.000000
+v -0.025024 -0.125802 -0.005823
+v -0.025462 -0.128007 -0.011250
+v -0.026160 -0.131514 -0.015910
+v -0.027069 -0.136084 -0.019486
+v -0.028128 -0.141406 -0.021733
+v -0.029264 -0.147118 -0.022500
+v -0.030400 -0.152829 -0.021733
+v -0.031458 -0.158152 -0.019486
+v -0.032367 -0.162722 -0.015910
+v -0.033065 -0.166229 -0.011250
+v -0.033504 -0.168434 -0.005823
+v -0.022516 -0.171024 -0.000000
+v -0.022416 -0.170264 0.005823
+v -0.022122 -0.168036 0.011250
+v -0.021656 -0.164490 0.015910
+v -0.021047 -0.159870 0.019486
+v -0.020339 -0.154490 0.021733
+v -0.019579 -0.148717 0.022500
+v -0.018819 -0.142943 0.021733
+v -0.018111 -0.137563 0.019486
+v -0.017502 -0.132943 0.015910
+v -0.017036 -0.129398 0.011250
+v -0.016742 -0.127169 0.005823
+v -0.016642 -0.126409 -0.000000
+v -0.016742 -0.127169 -0.005823
+v -0.017036 -0.129398 -0.011250
+v -0.017502 -0.132943 -0.015910
+v -0.018111 -0.137563 -0.019486
+v -0.018819 -0.142943 -0.021733
+v -0.019579 -0.148717 -0.022500
+v -0.020339 -0.154490 -0.021733
+v -0.021047 -0.159870 -0.019486
+v -0.021656 -0.164490 -0.015910
+v -0.022122 -0.168036 -0.011250
+v -0.022416 -0.170264 -0.005823
+v -0.011282 -0.172131 -0.000000
+v -0.011232 -0.171366 0.005823
+v -0.011085 -0.169123 0.011250
+v -0.010851 -0.165555 0.015910
+v -0.010546 -0.160905 0.019486
+v -0.010191 -0.155490 0.021733
+v -0.009810 -0.149679 0.022500
+v -0.009430 -0.143868 0.021733
+v -0.009075 -0.138453 0.019486
+v -0.008770 -0.133803 0.015910
+v -0.008536 -0.130235 0.011250
+v -0.008389 -0.127992 0.005823
+v -0.008339 -0.127227 -0.000000
+v -0.008389 -0.127992 -0.005823
+v -0.008536 -0.130235 -0.011250
+v -0.008770 -0.133803 -0.015910
+v -0.009075 -0.138453 -0.019486
+v -0.009430 -0.143868 -0.021733
+v -0.009810 -0.149679 -0.022500
+v -0.010191 -0.155490 -0.021733
+v -0.010546 -0.160905 -0.019486
+v -0.010851 -0.165555 -0.015910
+v -0.011085 -0.169123 -0.011250
+v -0.011232 -0.171366 -0.005823
+v 0.000000 -0.172500 -0.000000
+v 0.000000 -0.171733 0.005823
+v 0.000000 -0.169486 0.011250
+v 0.000000 -0.165910 0.015910
+v 0.000000 -0.161250 0.019486
+v 0.000000 -0.155823 0.021733
+v 0.000000 -0.150000 0.022500
+v 0.000000 -0.144177 0.021733
+v 0.000000 -0.138750 0.019486
+v 0.000000 -0.134090 0.015910
+v 0.000000 -0.130514 0.011250
+v 0.000000 -0.128267 0.005823
+v 0.000000 -0.127500 -0.000000
+v 0.000000 -0.128267 -0.005823
+v 0.000000 -0.130514 -0.011250
+v 0.000000 -0.134090 -0.015910
+v 0.000000 -0.138750 -0.019486
+v 0.000000 -0.144177 -0.021733
+v 0.000000 -0.150000 -0.022500
+v 0.000000 -0.155823 -0.021733
+v 0.000000 -0.161250 -0.019486
+v 0.000000 -0.165910 -0.015910
+v 0.000000 -0.169486 -0.011250
+v 0.000000 -0.171733 -0.005823
+v 0.011282 -0.172131 -0.000000
+v 0.011232 -0.171366 0.005823
+v 0.011085 -0.169123 0.011250
+v 0.010851 -0.165555 0.015910
+v 0.010546 -0.160905 0.019486
+v 0.010191 -0.155490 0.021733
+v 0.009810 -0.149679 0.022500
+v 0.009430 -0.143868 0.021733
+v 0.009075 -0.138453 0.019486
+v 0.008770 -0.133803 0.015910
+v 0.008536 -0.130235 0.011250
+v 0.008389 -0.127992 0.005823
+v 0.008339 -0.127227 -0.000000
+v 0.008389 -0.127992 -0.005823
+v 0.008536 -0.130235 -0.011250
+v 0.008770 -0.133803 -0.015910
+v 0.009075 -0.138453 -0.019486
+v 0.009430 -0.143868 -0.021733
+v 0.009810 -0.149679 -0.022500
+v 0.010191 -0.155490 -0.021733
+v 0.010546 -0.160905 -0.019486
+v 0.010851 -0.165555 -0.015910
+v 0.011085 -0.169123 -0.011250
+v 0.011232 -0.171366 -0.005823
+v 0.022516 -0.171024 -0.000000
+v 0.022416 -0.170264 0.005823
+v 0.022122 -0.168036 0.011250
+v 0.021656 -0.164491 0.015910
+v 0.021047 -0.159871 0.019486
+v 0.020339 -0.154490 0.021733
+v 0.019579 -0.148717 0.022500
+v 0.018819 -0.142943 0.021733
+v 0.018110 -0.137563 0.019486
+v 0.017502 -0.132943 0.015910
+v 0.017036 -0.129398 0.011250
+v 0.016742 -0.127169 0.005823
+v 0.016642 -0.126409 -0.000000
+v 0.016742 -0.127169 -0.005823
+v 0.017036 -0.129398 -0.011250
+v 0.017502 -0.132943 -0.015910
+v 0.018110 -0.137563 -0.019486
+v 0.018819 -0.142943 -0.021733
+v 0.019579 -0.148717 -0.022500
+v 0.020339 -0.154490 -0.021733
+v 0.021047 -0.159871 -0.019486
+v 0.021656 -0.164491 -0.015910
+v 0.022122 -0.168036 -0.011250
+v 0.022416 -0.170264 -0.005823
+v 0.033653 -0.169185 -0.000000
+v 0.033503 -0.168434 0.005823
+v 0.033065 -0.166229 0.011250
+v 0.032367 -0.162722 0.015910
+v 0.031458 -0.158152 0.019486
+v 0.030400 -0.152829 0.021733
+v 0.029264 -0.147118 0.022500
+v 0.028127 -0.141406 0.021733
+v 0.027069 -0.136084 0.019486
+v 0.026160 -0.131514 0.015910
+v 0.025462 -0.128007 0.011250
+v 0.025024 -0.125802 0.005823
+v 0.024874 -0.125050 -0.000000
+v 0.025024 -0.125802 -0.005823
+v 0.025462 -0.128007 -0.011250
+v 0.026160 -0.131514 -0.015910
+v 0.027069 -0.136084 -0.019486
+v 0.028127 -0.141406 -0.021733
+v 0.029264 -0.147118 -0.022500
+v 0.030400 -0.152829 -0.021733
+v 0.031458 -0.158152 -0.019486
+v 0.032367 -0.162722 -0.015910
+v 0.033065 -0.166229 -0.011250
+v 0.033503 -0.168434 -0.005823
+v 0.044646 -0.166622 -0.000000
+v 0.044448 -0.165882 0.005823
+v 0.043866 -0.163711 0.011250
+v 0.042941 -0.160257 0.015910
+v 0.041734 -0.155756 0.019486
+v 0.040330 -0.150514 0.021733
+v 0.038823 -0.144889 0.022500
+v 0.037316 -0.139264 0.021733
+v 0.035911 -0.134022 0.019486
+v 0.034705 -0.129521 0.015910
+v 0.033780 -0.126067 0.011250
+v 0.033198 -0.123896 0.005823
+v 0.032999 -0.123156 -0.000000
+v 0.033198 -0.123896 -0.005823
+v 0.033780 -0.126067 -0.011250
+v 0.034705 -0.129521 -0.015910
+v 0.035911 -0.134022 -0.019486
+v 0.037316 -0.139264 -0.021733
+v 0.038823 -0.144889 -0.022500
+v 0.040330 -0.150514 -0.021733
+v 0.041734 -0.155756 -0.019486
+v 0.042941 -0.160257 -0.015910
+v 0.043866 -0.163711 -0.011250
+v 0.044448 -0.165882 -0.005823
+v 0.055448 -0.163345 -0.000000
+v 0.055202 -0.162620 0.005823
+v 0.054479 -0.160491 0.011250
+v 0.053330 -0.157105 0.015910
+v 0.051832 -0.152693 0.019486
+v 0.050088 -0.147554 0.021733
+v 0.048216 -0.142040 0.022500
+v 0.046344 -0.136525 0.021733
+v 0.044600 -0.131387 0.019486
+v 0.043102 -0.126974 0.015910
+v 0.041952 -0.123588 0.011250
+v 0.041230 -0.121460 0.005823
+v 0.040983 -0.120734 -0.000000
+v 0.041230 -0.121460 -0.005823
+v 0.041952 -0.123588 -0.011250
+v 0.043102 -0.126974 -0.015910
+v 0.044600 -0.131387 -0.019486
+v 0.046344 -0.136525 -0.021733
+v 0.048216 -0.142040 -0.022500
+v 0.050088 -0.147554 -0.021733
+v 0.051832 -0.152693 -0.019486
+v 0.053330 -0.157105 -0.015910
+v 0.054479 -0.160491 -0.011250
+v 0.055202 -0.162620 -0.005823
+v 0.066013 -0.159369 -0.000000
+v 0.065720 -0.158661 0.005823
+v 0.064859 -0.156584 0.011250
+v 0.063491 -0.153281 0.015910
+v 0.061708 -0.148976 0.019486
+v 0.059631 -0.143962 0.021733
+v 0.057403 -0.138582 0.022500
+v 0.055174 -0.133202 0.021733
+v 0.053097 -0.128188 0.019486
+v 0.051314 -0.123883 0.015910
+v 0.049946 -0.120580 0.011250
+v 0.049086 -0.118503 0.005823
+v 0.048792 -0.117795 -0.000000
+v 0.049086 -0.118503 -0.005823
+v 0.049946 -0.120580 -0.011250
+v 0.051314 -0.123883 -0.015910
+v 0.053097 -0.128188 -0.019486
+v 0.055174 -0.133202 -0.021733
+v 0.057403 -0.138582 -0.022500
+v 0.059631 -0.143962 -0.021733
+v 0.061708 -0.148976 -0.019486
+v 0.063491 -0.153281 -0.015910
+v 0.064859 -0.156584 -0.011250
+v 0.065720 -0.158661 -0.005823
+v 0.076295 -0.154711 -0.000000
+v 0.075956 -0.154023 0.005823
+v 0.074962 -0.152007 0.011250
+v 0.073380 -0.148800 0.015910
+v 0.071319 -0.144621 0.019486
+v 0.068919 -0.139754 0.021733
+v 0.066343 -0.134531 0.022500
+v 0.063768 -0.129308 0.021733
+v 0.061368 -0.124441 0.019486
+v 0.059307 -0.120262 0.015910
+v 0.057725 -0.117055 0.011250
+v 0.056731 -0.115039 0.005823
+v 0.056392 -0.114351 -0.000000
+v 0.056731 -0.115039 -0.005823
+v 0.057725 -0.117055 -0.011250
+v 0.059307 -0.120262 -0.015910
+v 0.061368 -0.124441 -0.019486
+v 0.063768 -0.129308 -0.021733
+v 0.066343 -0.134531 -0.022500
+v 0.068919 -0.139754 -0.021733
+v 0.071319 -0.144621 -0.019486
+v 0.073380 -0.148800 -0.015910
+v 0.074962 -0.152007 -0.011250
+v 0.075956 -0.154023 -0.005823
+v 0.086250 -0.149389 -0.000000
+v 0.085867 -0.148725 0.005823
+v 0.084743 -0.146779 0.011250
+v 0.082955 -0.143682 0.015910
+v 0.080625 -0.139647 0.019486
+v 0.077912 -0.134947 0.021733
+v 0.075000 -0.129904 0.022500
+v 0.072088 -0.124861 0.021733
+v 0.069375 -0.120161 0.019486
+v 0.067045 -0.116125 0.015910
+v 0.065257 -0.113029 0.011250
+v 0.064133 -0.111082 0.005823
+v 0.063750 -0.110418 -0.000000
+v 0.064133 -0.111082 -0.005823
+v 0.065257 -0.113029 -0.011250
+v 0.067045 -0.116125 -0.015910
+v 0.069375 -0.120161 -0.019486
+v 0.072088 -0.124861 -0.021733
+v 0.075000 -0.129904 -0.022500
+v 0.077912 -0.134947 -0.021733
+v 0.080625 -0.139647 -0.019486
+v 0.082955 -0.143682 -0.015910
+v 0.084743 -0.146779 -0.011250
+v 0.085867 -0.148725 -0.005823
+v 0.095836 -0.143429 -0.000000
+v 0.095410 -0.142791 0.005823
+v 0.094161 -0.140922 0.011250
+v 0.092175 -0.137949 0.015910
+v 0.089586 -0.134074 0.019486
+v 0.086571 -0.129562 0.021733
+v 0.083336 -0.124720 0.022500
+v 0.080100 -0.119878 0.021733
+v 0.077085 -0.115366 0.019486
+v 0.074496 -0.111492 0.015910
+v 0.072510 -0.108519 0.011250
+v 0.071261 -0.106650 0.005823
+v 0.070835 -0.106012 -0.000000
+v 0.071261 -0.106650 -0.005823
+v 0.072510 -0.108519 -0.011250
+v 0.074496 -0.111492 -0.015910
+v 0.077085 -0.115366 -0.019486
+v 0.080100 -0.119878 -0.021733
+v 0.083336 -0.124720 -0.022500
+v 0.086571 -0.129562 -0.021733
+v 0.089586 -0.134074 -0.019486
+v 0.092175 -0.137949 -0.015910
+v 0.094161 -0.140922 -0.011250
+v 0.095410 -0.142791 -0.005823
+v 0.105011 -0.136853 -0.000000
+v 0.104545 -0.136245 0.005823
+v 0.103176 -0.134462 0.011250
+v 0.101000 -0.131625 0.015910
+v 0.098163 -0.127928 0.019486
+v 0.094859 -0.123623 0.021733
+v 0.091314 -0.119003 0.022500
+v 0.087769 -0.114383 0.021733
+v 0.084466 -0.110078 0.019486
+v 0.081629 -0.106381 0.015910
+v 0.079452 -0.103544 0.011250
+v 0.078084 -0.101761 0.005823
+v 0.077617 -0.101153 -0.000000
+v 0.078084 -0.101761 -0.005823
+v 0.079452 -0.103544 -0.011250
+v 0.081629 -0.106381 -0.015910
+v 0.084466 -0.110078 -0.019486
+v 0.087769 -0.114383 -0.021733
+v 0.091314 -0.119003 -0.022500
+v 0.094859 -0.123623 -0.021733
+v 0.098163 -0.127928 -0.019486
+v 0.101000 -0.131625 -0.015910
+v 0.103176 -0.134462 -0.011250
+v 0.104545 -0.136245 -0.005823
+v 0.113737 -0.129692 -0.000000
+v 0.113232 -0.129116 0.005823
+v 0.111750 -0.127426 0.011250
+v 0.109392 -0.124738 0.015910
+v 0.106319 -0.121234 0.019486
+v 0.102741 -0.117154 0.021733
+v 0.098902 -0.112776 0.022500
+v 0.095062 -0.108398 0.021733
+v 0.091484 -0.104318 0.019486
+v 0.088412 -0.100814 0.015910
+v 0.086054 -0.098126 0.011250
+v 0.084572 -0.096436 0.005823
+v 0.084067 -0.095860 -0.000000
+v 0.084572 -0.096436 -0.005823
+v 0.086054 -0.098126 -0.011250
+v 0.088412 -0.100814 -0.015910
+v 0.091484 -0.104318 -0.019486
+v 0.095062 -0.108398 -0.021733
+v 0.098902 -0.112776 -0.022500
+v 0.102741 -0.117154 -0.021733
+v 0.106319 -0.121234 -0.019486
+v 0.109392 -0.124738 -0.015910
+v 0.111750 -0.127426 -0.011250
+v 0.113232 -0.129116 -0.005823
+v 0.121976 -0.121976 -0.000000
+v 0.121434 -0.121434 0.005823
+v 0.119844 -0.119844 0.011250
+v 0.117316 -0.117316 0.015910
+v 0.114021 -0.114021 0.019486
+v 0.110184 -0.110184 0.021733
+v 0.106066 -0.106066 0.022500
+v 0.101948 -0.101948 0.021733
+v 0.098111 -0.098111 0.019486
+v 0.094816 -0.094816 0.015910
+v 0.092288 -0.092288 0.011250
+v 0.090698 -0.090698 0.005823
+v 0.090156 -0.090156 -0.000000
+v 0.090698 -0.090698 -0.005823
+v 0.092288 -0.092288 -0.011250
+v 0.094816 -0.094816 -0.015910
+v 0.098111 -0.098111 -0.019486
+v 0.101948 -0.101948 -0.021733
+v 0.106066 -0.106066 -0.022500
+v 0.110184 -0.110184 -0.021733
+v 0.114021 -0.114021 -0.019486
+v 0.117316 -0.117316 -0.015910
+v 0.119844 -0.119844 -0.011250
+v 0.121434 -0.121434 -0.005823
+v 0.129692 -0.113737 -0.000000
+v 0.129116 -0.113232 0.005823
+v 0.127426 -0.111750 0.011250
+v 0.124738 -0.109392 0.015910
+v 0.121234 -0.106319 0.019486
+v 0.117154 -0.102742 0.021733
+v 0.112776 -0.098902 0.022500
+v 0.108398 -0.095062 0.021733
+v 0.104318 -0.091484 0.019486
+v 0.100814 -0.088412 0.015910
+v 0.098126 -0.086054 0.011250
+v 0.096436 -0.084572 0.005823
+v 0.095860 -0.084067 -0.000000
+v 0.096436 -0.084572 -0.005823
+v 0.098126 -0.086054 -0.011250
+v 0.100814 -0.088412 -0.015910
+v 0.104318 -0.091484 -0.019486
+v 0.108398 -0.095062 -0.021733
+v 0.112776 -0.098902 -0.022500
+v 0.117154 -0.102742 -0.021733
+v 0.121234 -0.106319 -0.019486
+v 0.124738 -0.109392 -0.015910
+v 0.127426 -0.111750 -0.011250
+v 0.129116 -0.113232 -0.005823
+v 0.136853 -0.105011 -0.000000
+v 0.136245 -0.104545 0.005823
+v 0.134462 -0.103176 0.011250
+v 0.131625 -0.101000 0.015910
+v 0.127928 -0.098163 0.019486
+v 0.123623 -0.094859 0.021733
+v 0.119003 -0.091314 0.022500
+v 0.114383 -0.087769 0.021733
+v 0.110078 -0.084466 0.019486
+v 0.106381 -0.081629 0.015910
+v 0.103544 -0.079452 0.011250
+v 0.101761 -0.078084 0.005823
+v 0.101153 -0.077617 -0.000000
+v 0.101761 -0.078084 -0.005823
+v 0.103544 -0.079452 -0.011250
+v 0.106381 -0.081629 -0.015910
+v 0.110078 -0.084466 -0.019486
+v 0.114383 -0.087769 -0.021733
+v 0.119003 -0.091314 -0.022500
+v 0.123623 -0.094859 -0.021733
+v 0.127928 -0.098163 -0.019486
+v 0.131625 -0.101000 -0.015910
+v 0.134462 -0.103176 -0.011250
+v 0.136245 -0.104545 -0.005823
+v 0.143429 -0.095836 -0.000000
+v 0.142791 -0.095410 0.005823
+v 0.140922 -0.094161 0.011250
+v 0.137949 -0.092175 0.015910
+v 0.134074 -0.089586 0.019486
+v 0.129562 -0.086571 0.021733
+v 0.124720 -0.083336 0.022500
+v 0.119878 -0.080100 0.021733
+v 0.115366 -0.077085 0.019486
+v 0.111492 -0.074496 0.015910
+v 0.108519 -0.072510 0.011250
+v 0.106650 -0.071261 0.005823
+v 0.106012 -0.070835 -0.000000
+v 0.106650 -0.071261 -0.005823
+v 0.108519 -0.072510 -0.011250
+v 0.111492 -0.074496 -0.015910
+v 0.115366 -0.077085 -0.019486
+v 0.119878 -0.080100 -0.021733
+v 0.124720 -0.083336 -0.022500
+v 0.129562 -0.086571 -0.021733
+v 0.134074 -0.089586 -0.019486
+v 0.137949 -0.092175 -0.015910
+v 0.140922 -0.094161 -0.011250
+v 0.142791 -0.095410 -0.005823
+v 0.149389 -0.086250 -0.000000
+v 0.148725 -0.085867 0.005823
+v 0.146779 -0.084743 0.011250
+v 0.143682 -0.082955 0.015910
+v 0.139647 -0.080625 0.019486
+v 0.134947 -0.077912 0.021733
+v 0.129904 -0.075000 0.022500
+v 0.124861 -0.072088 0.021733
+v 0.120161 -0.069375 0.019486
+v 0.116125 -0.067045 0.015910
+v 0.113029 -0.065257 0.011250
+v 0.111082 -0.064133 0.005823
+v 0.110418 -0.063750 -0.000000
+v 0.111082 -0.064133 -0.005823
+v 0.113029 -0.065257 -0.011250
+v 0.116125 -0.067045 -0.015910
+v 0.120161 -0.069375 -0.019486
+v 0.124861 -0.072088 -0.021733
+v 0.129904 -0.075000 -0.022500
+v 0.134947 -0.077912 -0.021733
+v 0.139647 -0.080625 -0.019486
+v 0.143682 -0.082955 -0.015910
+v 0.146779 -0.084743 -0.011250
+v 0.148725 -0.085867 -0.005823
+v 0.154711 -0.076295 -0.000000
+v 0.154023 -0.075956 0.005823
+v 0.152007 -0.074962 0.011250
+v 0.148800 -0.073380 0.015910
+v 0.144621 -0.071319 0.019486
+v 0.139754 -0.068919 0.021733
+v 0.134531 -0.066343 0.022500
+v 0.129308 -0.063768 0.021733
+v 0.124441 -0.061368 0.019486
+v 0.120262 -0.059307 0.015910
+v 0.117055 -0.057725 0.011250
+v 0.115039 -0.056731 0.005823
+v 0.114351 -0.056392 -0.000000
+v 0.115039 -0.056731 -0.005823
+v 0.117055 -0.057725 -0.011250
+v 0.120262 -0.059307 -0.015910
+v 0.124441 -0.061368 -0.019486
+v 0.129308 -0.063768 -0.021733
+v 0.134531 -0.066343 -0.022500
+v 0.139754 -0.068919 -0.021733
+v 0.144621 -0.071319 -0.019486
+v 0.148800 -0.073380 -0.015910
+v 0.152007 -0.074962 -0.011250
+v 0.154023 -0.075956 -0.005823
+v 0.159369 -0.066013 -0.000000
+v 0.158661 -0.065720 0.005823
+v 0.156584 -0.064859 0.011250
+v 0.153281 -0.063491 0.015910
+v 0.148976 -0.061708 0.019486
+v 0.143962 -0.059631 0.021733
+v 0.138582 -0.057403 0.022500
+v 0.133202 -0.055174 0.021733
+v 0.128188 -0.053097 0.019486
+v 0.123883 -0.051314 0.015910
+v 0.120580 -0.049946 0.011250
+v 0.118503 -0.049086 0.005823
+v 0.117795 -0.048792 -0.000000
+v 0.118503 -0.049086 -0.005823
+v 0.120580 -0.049946 -0.011250
+v 0.123883 -0.051314 -0.015910
+v 0.128188 -0.053097 -0.019486
+v 0.133202 -0.055174 -0.021733
+v 0.138582 -0.057403 -0.022500
+v 0.143962 -0.059631 -0.021733
+v 0.148976 -0.061708 -0.019486
+v 0.153281 -0.063491 -0.015910
+v 0.156584 -0.064859 -0.011250
+v 0.158661 -0.065720 -0.005823
+v 0.163345 -0.055448 -0.000000
+v 0.162619 -0.055202 0.005823
+v 0.160491 -0.054479 0.011250
+v 0.157105 -0.053330 0.015910
+v 0.152692 -0.051832 0.019486
+v 0.147554 -0.050088 0.021733
+v 0.142040 -0.048216 0.022500
+v 0.136525 -0.046344 0.021733
+v 0.131387 -0.044600 0.019486
+v 0.126974 -0.043102 0.015910
+v 0.123588 -0.041953 0.011250
+v 0.121460 -0.041230 0.005823
+v 0.120734 -0.040984 -0.000000
+v 0.121460 -0.041230 -0.005823
+v 0.123588 -0.041953 -0.011250
+v 0.126974 -0.043102 -0.015910
+v 0.131387 -0.044600 -0.019486
+v 0.136525 -0.046344 -0.021733
+v 0.142040 -0.048216 -0.022500
+v 0.147554 -0.050088 -0.021733
+v 0.152692 -0.051832 -0.019486
+v 0.157105 -0.053330 -0.015910
+v 0.160491 -0.054479 -0.011250
+v 0.162619 -0.055202 -0.005823
+v 0.166622 -0.044646 -0.000000
+v 0.165882 -0.044448 0.005823
+v 0.163711 -0.043866 0.011250
+v 0.160257 -0.042941 0.015910
+v 0.155756 -0.041735 0.019486
+v 0.150514 -0.040330 0.021733
+v 0.144889 -0.038823 0.022500
+v 0.139264 -0.037316 0.021733
+v 0.134022 -0.035911 0.019486
+v 0.129521 -0.034705 0.015910
+v 0.126067 -0.033780 0.011250
+v 0.123896 -0.033198 0.005823
+v 0.123156 -0.032999 -0.000000
+v 0.123896 -0.033198 -0.005823
+v 0.126067 -0.033780 -0.011250
+v 0.129521 -0.034705 -0.015910
+v 0.134022 -0.035911 -0.019486
+v 0.139264 -0.037316 -0.021733
+v 0.144889 -0.038823 -0.022500
+v 0.150514 -0.040330 -0.021733
+v 0.155756 -0.041735 -0.019486
+v 0.160257 -0.042941 -0.015910
+v 0.163711 -0.043866 -0.011250
+v 0.165882 -0.044448 -0.005823
+v 0.169185 -0.033653 -0.000000
+v 0.168434 -0.033503 0.005823
+v 0.166229 -0.033065 0.011250
+v 0.162722 -0.032367 0.015910
+v 0.158152 -0.031458 0.019486
+v 0.152829 -0.030400 0.021733
+v 0.147118 -0.029264 0.022500
+v 0.141406 -0.028127 0.021733
+v 0.136084 -0.027069 0.019486
+v 0.131514 -0.026160 0.015910
+v 0.128007 -0.025462 0.011250
+v 0.125802 -0.025024 0.005823
+v 0.125050 -0.024874 -0.000000
+v 0.125802 -0.025024 -0.005823
+v 0.128007 -0.025462 -0.011250
+v 0.131514 -0.026160 -0.015910
+v 0.136084 -0.027069 -0.019486
+v 0.141406 -0.028127 -0.021733
+v 0.147118 -0.029264 -0.022500
+v 0.152829 -0.030400 -0.021733
+v 0.158152 -0.031458 -0.019486
+v 0.162722 -0.032367 -0.015910
+v 0.166229 -0.033065 -0.011250
+v 0.168434 -0.033503 -0.005823
+v 0.171024 -0.022516 -0.000000
+v 0.170264 -0.022416 0.005823
+v 0.168036 -0.022122 0.011250
+v 0.164491 -0.021656 0.015910
+v 0.159871 -0.021047 0.019486
+v 0.154490 -0.020339 0.021733
+v 0.148717 -0.019579 0.022500
+v 0.142943 -0.018819 0.021733
+v 0.137563 -0.018111 0.019486
+v 0.132943 -0.017502 0.015910
+v 0.129398 -0.017036 0.011250
+v 0.127169 -0.016742 0.005823
+v 0.126409 -0.016642 -0.000000
+v 0.127169 -0.016742 -0.005823
+v 0.129398 -0.017036 -0.011250
+v 0.132943 -0.017502 -0.015910
+v 0.137563 -0.018111 -0.019486
+v 0.142943 -0.018819 -0.021733
+v 0.148717 -0.019579 -0.022500
+v 0.154490 -0.020339 -0.021733
+v 0.159871 -0.021047 -0.019486
+v 0.164491 -0.021656 -0.015910
+v 0.168036 -0.022122 -0.011250
+v 0.170264 -0.022416 -0.005823
+v 0.172131 -0.011282 -0.000000
+v 0.171366 -0.011232 0.005823
+v 0.169123 -0.011085 0.011250
+v 0.165555 -0.010851 0.015910
+v 0.160905 -0.010546 0.019486
+v 0.155490 -0.010191 0.021733
+v 0.149679 -0.009810 0.022500
+v 0.143868 -0.009430 0.021733
+v 0.138453 -0.009075 0.019486
+v 0.133803 -0.008770 0.015910
+v 0.130235 -0.008536 0.011250
+v 0.127992 -0.008389 0.005823
+v 0.127227 -0.008339 -0.000000
+v 0.127992 -0.008389 -0.005823
+v 0.130235 -0.008536 -0.011250
+v 0.133803 -0.008770 -0.015910
+v 0.138453 -0.009075 -0.019486
+v 0.143868 -0.009430 -0.021733
+v 0.149679 -0.009810 -0.022500
+v 0.155490 -0.010191 -0.021733
+v 0.160905 -0.010546 -0.019486
+v 0.165555 -0.010851 -0.015910
+v 0.169123 -0.011085 -0.011250
+v 0.171366 -0.011232 -0.005823
+vn 0.990900 0.032400 0.130500
+vn 0.923500 0.030200 0.382500
+vn 0.793100 0.026000 0.608600
+vn 0.608600 0.019900 0.793200
+vn 0.382700 0.012500 0.923800
+vn 0.130500 0.004300 0.991400
+vn -0.130500 -0.004300 0.991400
+vn -0.382700 -0.012500 0.923800
+vn -0.608600 -0.019900 0.793200
+vn -0.793100 -0.026000 0.608600
+vn -0.923500 -0.030200 0.382500
+vn -0.990900 -0.032400 0.130500
+vn -0.990900 -0.032400 -0.130500
+vn -0.923500 -0.030200 -0.382500
+vn -0.793100 -0.026000 -0.608600
+vn -0.608600 -0.019900 -0.793200
+vn -0.382700 -0.012500 -0.923800
+vn -0.130500 -0.004300 -0.991400
+vn 0.130500 0.004300 -0.991400
+vn 0.382700 0.012500 -0.923800
+vn 0.608600 0.019900 -0.793200
+vn 0.793100 0.026000 -0.608600
+vn 0.923500 0.030200 -0.382500
+vn 0.990900 0.032400 -0.130500
+vn 0.986700 0.097200 0.130500
+vn 0.919500 0.090600 0.382500
+vn 0.789700 0.077800 0.608600
+vn 0.606000 0.059700 0.793200
+vn 0.381000 0.037500 0.923800
+vn 0.130000 0.012800 0.991400
+vn -0.130000 -0.012800 0.991400
+vn -0.381000 -0.037500 0.923800
+vn -0.606000 -0.059700 0.793200
+vn -0.789700 -0.077800 0.608600
+vn -0.919500 -0.090600 0.382500
+vn -0.986700 -0.097200 0.130500
+vn -0.986700 -0.097200 -0.130500
+vn -0.919500 -0.090600 -0.382500
+vn -0.789700 -0.077800 -0.608600
+vn -0.606000 -0.059700 -0.793200
+vn -0.381000 -0.037500 -0.923800
+vn -0.130000 -0.012800 -0.991400
+vn 0.130000 0.012800 -0.991400
+vn 0.381000 0.037500 -0.923800
+vn 0.606000 0.059700 -0.793200
+vn 0.789700 0.077800 -0.608600
+vn 0.919500 0.090600 -0.382500
+vn 0.986700 0.097200 -0.130500
+vn 0.978200 0.161500 0.130500
+vn 0.911600 0.150500 0.382500
+vn 0.782900 0.129300 0.608600
+vn 0.600800 0.099200 0.793200
+vn 0.377700 0.062400 0.923800
+vn 0.128900 0.021300 0.991400
+vn -0.128900 -0.021300 0.991400
+vn -0.377700 -0.062400 0.923800
+vn -0.600800 -0.099200 0.793200
+vn -0.782900 -0.129300 0.608600
+vn -0.911600 -0.150500 0.382500
+vn -0.978200 -0.161500 0.130500
+vn -0.978200 -0.161500 -0.130500
+vn -0.911600 -0.150500 -0.382500
+vn -0.782900 -0.129300 -0.608600
+vn -0.600800 -0.099200 -0.793200
+vn -0.377700 -0.062400 -0.923800
+vn -0.128900 -0.021300 -0.991400
+vn 0.128900 0.021300 -0.991400
+vn 0.377700 0.062400 -0.923800
+vn 0.600800 0.099200 -0.793200
+vn 0.782900 0.129300 -0.608600
+vn 0.911600 0.150500 -0.382500
+vn 0.978200 0.161500 -0.130500
+vn 0.965600 0.225100 0.130500
+vn 0.899800 0.209800 0.382500
+vn 0.772800 0.180200 0.608600
+vn 0.593100 0.138300 0.793200
+vn 0.372900 0.086900 0.923800
+vn 0.127200 0.029700 0.991400
+vn -0.127200 -0.029700 0.991400
+vn -0.372900 -0.086900 0.923800
+vn -0.593100 -0.138300 0.793200
+vn -0.772800 -0.180200 0.608600
+vn -0.899800 -0.209800 0.382500
+vn -0.965600 -0.225100 0.130500
+vn -0.965600 -0.225100 -0.130500
+vn -0.899800 -0.209800 -0.382500
+vn -0.772800 -0.180200 -0.608600
+vn -0.593100 -0.138300 -0.793200
+vn -0.372900 -0.086900 -0.923800
+vn -0.127200 -0.029700 -0.991400
+vn 0.127200 0.029700 -0.991400
+vn 0.372900 0.086900 -0.923800
+vn 0.593100 0.138300 -0.793200
+vn 0.772800 0.180200 -0.608600
+vn 0.899800 0.209800 -0.382500
+vn 0.965600 0.225100 -0.130500
+vn 0.948800 0.287800 0.130500
+vn 0.884200 0.268200 0.382500
+vn 0.759300 0.230300 0.608600
+vn 0.582700 0.176800 0.793200
+vn 0.366400 0.111100 0.923800
+vn 0.125000 0.037900 0.991400
+vn -0.125000 -0.037900 0.991400
+vn -0.366400 -0.111100 0.923800
+vn -0.582700 -0.176800 0.793200
+vn -0.759300 -0.230300 0.608600
+vn -0.884200 -0.268200 0.382500
+vn -0.948800 -0.287800 0.130500
+vn -0.948800 -0.287800 -0.130500
+vn -0.884200 -0.268200 -0.382500
+vn -0.759300 -0.230300 -0.608600
+vn -0.582700 -0.176800 -0.793200
+vn -0.366400 -0.111100 -0.923800
+vn -0.125000 -0.037900 -0.991400
+vn 0.125000 0.037900 -0.991400
+vn 0.366400 0.111100 -0.923800
+vn 0.582700 0.176800 -0.793200
+vn 0.759300 0.230300 -0.608600
+vn 0.884200 0.268200 -0.382500
+vn 0.948800 0.287800 -0.130500
+vn 0.927900 0.349200 0.130500
+vn 0.864700 0.325500 0.382500
+vn 0.742700 0.279500 0.608600
+vn 0.569900 0.214500 0.793200
+vn 0.358300 0.134900 0.923800
+vn 0.122200 0.046000 0.991400
+vn -0.122200 -0.046000 0.991400
+vn -0.358300 -0.134900 0.923800
+vn -0.569900 -0.214500 0.793200
+vn -0.742700 -0.279500 0.608600
+vn -0.864700 -0.325500 0.382500
+vn -0.927900 -0.349200 0.130500
+vn -0.927900 -0.349200 -0.130500
+vn -0.864700 -0.325500 -0.382500
+vn -0.742700 -0.279500 -0.608600
+vn -0.569900 -0.214500 -0.793200
+vn -0.358300 -0.134900 -0.923800
+vn -0.122200 -0.046000 -0.991400
+vn 0.122200 0.046000 -0.991400
+vn 0.358300 0.134900 -0.923800
+vn 0.569900 0.214500 -0.793200
+vn 0.742700 0.279500 -0.608600
+vn 0.864700 0.325500 -0.382500
+vn 0.927900 0.349200 -0.130500
+vn 0.903100 0.409200 0.130500
+vn 0.841600 0.381300 0.382500
+vn 0.722800 0.327500 0.608600
+vn 0.554700 0.251300 0.793200
+vn 0.348700 0.158000 0.923800
+vn 0.119000 0.053900 0.991400
+vn -0.119000 -0.053900 0.991400
+vn -0.348700 -0.158000 0.923800
+vn -0.554700 -0.251300 0.793200
+vn -0.722800 -0.327500 0.608600
+vn -0.841600 -0.381300 0.382500
+vn -0.903100 -0.409200 0.130500
+vn -0.903100 -0.409200 -0.130500
+vn -0.841600 -0.381300 -0.382500
+vn -0.722800 -0.327500 -0.608600
+vn -0.554700 -0.251300 -0.793200
+vn -0.348700 -0.158000 -0.923800
+vn -0.119000 -0.053900 -0.991400
+vn 0.119000 0.053900 -0.991400
+vn 0.348700 0.158000 -0.923800
+vn 0.554700 0.251300 -0.793200
+vn 0.722800 0.327500 -0.608600
+vn 0.841600 0.381300 -0.382500
+vn 0.903100 0.409200 -0.130500
+vn 0.874400 0.467400 0.130500
+vn 0.814900 0.435600 0.382500
+vn 0.699800 0.374100 0.608600
+vn 0.537100 0.287100 0.793200
+vn 0.337700 0.180500 0.923800
+vn 0.115200 0.061600 0.991400
+vn -0.115200 -0.061600 0.991400
+vn -0.337700 -0.180500 0.923800
+vn -0.537100 -0.287100 0.793200
+vn -0.699800 -0.374100 0.608600
+vn -0.814900 -0.435500 0.382500
+vn -0.874400 -0.467400 0.130500
+vn -0.874400 -0.467400 -0.130500
+vn -0.814900 -0.435500 -0.382500
+vn -0.699800 -0.374100 -0.608600
+vn -0.537100 -0.287100 -0.793200
+vn -0.337700 -0.180500 -0.923800
+vn -0.115200 -0.061600 -0.991400
+vn 0.115200 0.061600 -0.991400
+vn 0.337700 0.180500 -0.923800
+vn 0.537100 0.287100 -0.793200
+vn 0.699800 0.374100 -0.608600
+vn 0.814900 0.435500 -0.382500
+vn 0.874400 0.467400 -0.130500
+vn 0.841900 0.523600 0.130500
+vn 0.784600 0.487900 0.382500
+vn 0.673800 0.419000 0.608600
+vn 0.517100 0.321600 0.793200
+vn 0.325100 0.202200 0.923800
+vn 0.110900 0.069000 0.991400
+vn -0.110900 -0.069000 0.991400
+vn -0.325100 -0.202200 0.923800
+vn -0.517100 -0.321600 0.793200
+vn -0.673900 -0.419000 0.608600
+vn -0.784600 -0.487900 0.382500
+vn -0.841900 -0.523600 0.130500
+vn -0.841900 -0.523600 -0.130500
+vn -0.784600 -0.487900 -0.382500
+vn -0.673900 -0.419000 -0.608600
+vn -0.517100 -0.321600 -0.793200
+vn -0.325100 -0.202200 -0.923800
+vn -0.110900 -0.069000 -0.991400
+vn 0.110900 0.069000 -0.991400
+vn 0.325100 0.202200 -0.923800
+vn 0.517100 0.321600 -0.793200
+vn 0.673800 0.419000 -0.608600
+vn 0.784600 0.487900 -0.382500
+vn 0.841900 0.523600 -0.130500
+vn 0.805900 0.577500 0.130500
+vn 0.751000 0.538200 0.382500
+vn 0.645000 0.462200 0.608600
+vn 0.495000 0.354700 0.793200
+vn 0.311200 0.223000 0.923800
+vn 0.106200 0.076100 0.991400
+vn -0.106200 -0.076100 0.991400
+vn -0.311200 -0.223000 0.923800
+vn -0.495000 -0.354700 0.793200
+vn -0.645000 -0.462200 0.608600
+vn -0.751000 -0.538200 0.382500
+vn -0.805900 -0.577500 0.130500
+vn -0.805900 -0.577500 -0.130500
+vn -0.751000 -0.538200 -0.382500
+vn -0.645000 -0.462200 -0.608600
+vn -0.495000 -0.354700 -0.793200
+vn -0.311200 -0.223000 -0.923800
+vn -0.106200 -0.076100 -0.991400
+vn 0.106200 0.076100 -0.991400
+vn 0.311200 0.223000 -0.923800
+vn 0.495000 0.354700 -0.793200
+vn 0.645000 0.462200 -0.608600
+vn 0.751000 0.538200 -0.382500
+vn 0.805900 0.577500 -0.130500
+vn 0.766400 0.629000 0.130500
+vn 0.714200 0.586100 0.382500
+vn 0.613400 0.503400 0.608600
+vn 0.470700 0.386300 0.793200
+vn 0.296000 0.242900 0.923800
+vn 0.101000 0.082800 0.991400
+vn -0.101000 -0.082800 0.991400
+vn -0.296000 -0.242900 0.923800
+vn -0.470700 -0.386300 0.793200
+vn -0.613400 -0.503400 0.608600
+vn -0.714200 -0.586100 0.382500
+vn -0.766400 -0.629000 0.130500
+vn -0.766400 -0.629000 -0.130500
+vn -0.714200 -0.586100 -0.382500
+vn -0.613400 -0.503400 -0.608600
+vn -0.470700 -0.386300 -0.793200
+vn -0.296000 -0.242900 -0.923800
+vn -0.101000 -0.082800 -0.991400
+vn 0.101000 0.082800 -0.991400
+vn 0.296000 0.242900 -0.923800
+vn 0.470700 0.386300 -0.793200
+vn 0.613400 0.503400 -0.608600
+vn 0.714200 0.586100 -0.382500
+vn 0.766400 0.629000 -0.130500
+vn 0.723600 0.677800 0.130500
+vn 0.674400 0.631600 0.382500
+vn 0.579200 0.542400 0.608600
+vn 0.444500 0.416300 0.793200
+vn 0.279400 0.261700 0.923800
+vn 0.095300 0.089300 0.991400
+vn -0.095300 -0.089300 0.991400
+vn -0.279400 -0.261700 0.923800
+vn -0.444500 -0.416300 0.793200
+vn -0.579200 -0.542400 0.608600
+vn -0.674400 -0.631600 0.382500
+vn -0.723600 -0.677700 0.130500
+vn -0.723600 -0.677800 -0.130500
+vn -0.674400 -0.631600 -0.382500
+vn -0.579200 -0.542400 -0.608600
+vn -0.444500 -0.416300 -0.793200
+vn -0.279400 -0.261700 -0.923800
+vn -0.095300 -0.089300 -0.991400
+vn 0.095300 0.089300 -0.991400
+vn 0.279400 0.261700 -0.923800
+vn 0.444500 0.416300 -0.793200
+vn 0.579200 0.542400 -0.608600
+vn 0.674400 0.631600 -0.382500
+vn 0.723600 0.677800 -0.130500
+vn 0.677800 0.723600 0.130500
+vn 0.631600 0.674400 0.382500
+vn 0.542400 0.579200 0.608600
+vn 0.416300 0.444500 0.793200
+vn 0.261700 0.279400 0.923800
+vn 0.089300 0.095300 0.991400
+vn -0.089300 -0.095300 0.991400
+vn -0.261700 -0.279400 0.923800
+vn -0.416300 -0.444500 0.793200
+vn -0.542400 -0.579200 0.608600
+vn -0.631600 -0.674400 0.382500
+vn -0.677800 -0.723600 0.130500
+vn -0.677800 -0.723600 -0.130500
+vn -0.631600 -0.674400 -0.382500
+vn -0.542400 -0.579200 -0.608600
+vn -0.416300 -0.444500 -0.793200
+vn -0.261700 -0.279400 -0.923800
+vn -0.089300 -0.095300 -0.991400
+vn 0.089300 0.095300 -0.991400
+vn 0.261700 0.279400 -0.923800
+vn 0.416300 0.444500 -0.793200
+vn 0.542400 0.579200 -0.608600
+vn 0.631600 0.674400 -0.382500
+vn 0.677800 0.723600 -0.130500
+vn 0.629000 0.766400 0.130500
+vn 0.586100 0.714200 0.382500
+vn 0.503400 0.613400 0.608600
+vn 0.386300 0.470700 0.793200
+vn 0.242900 0.296000 0.923800
+vn 0.082800 0.101000 0.991400
+vn -0.082800 -0.101000 0.991400
+vn -0.242900 -0.296000 0.923800
+vn -0.386300 -0.470700 0.793200
+vn -0.503400 -0.613400 0.608600
+vn -0.586100 -0.714200 0.382500
+vn -0.629000 -0.766400 0.130500
+vn -0.629000 -0.766400 -0.130500
+vn -0.586100 -0.714200 -0.382500
+vn -0.503400 -0.613400 -0.608600
+vn -0.386300 -0.470700 -0.793200
+vn -0.242900 -0.296000 -0.923800
+vn -0.082800 -0.101000 -0.991400
+vn 0.082800 0.101000 -0.991400
+vn 0.242900 0.296000 -0.923800
+vn 0.386300 0.470700 -0.793200
+vn 0.503400 0.613400 -0.608600
+vn 0.586100 0.714200 -0.382500
+vn 0.629000 0.766400 -0.130500
+vn 0.577500 0.805900 0.130500
+vn 0.538200 0.751000 0.382500
+vn 0.462200 0.645000 0.608600
+vn 0.354700 0.495000 0.793200
+vn 0.223000 0.311200 0.923800
+vn 0.076100 0.106200 0.991400
+vn -0.076100 -0.106200 0.991400
+vn -0.223000 -0.311200 0.923800
+vn -0.354700 -0.495000 0.793200
+vn -0.462200 -0.645000 0.608600
+vn -0.538200 -0.751000 0.382500
+vn -0.577500 -0.805900 0.130500
+vn -0.577500 -0.805900 -0.130500
+vn -0.538200 -0.751000 -0.382500
+vn -0.462200 -0.645000 -0.608600
+vn -0.354700 -0.495000 -0.793200
+vn -0.223000 -0.311200 -0.923800
+vn -0.076100 -0.106200 -0.991400
+vn 0.076100 0.106200 -0.991400
+vn 0.223000 0.311200 -0.923800
+vn 0.354700 0.495000 -0.793200
+vn 0.462200 0.645000 -0.608600
+vn 0.538200 0.751000 -0.382500
+vn 0.577500 0.805900 -0.130500
+vn 0.523600 0.841900 0.130500
+vn 0.487900 0.784600 0.382500
+vn 0.419000 0.673800 0.608600
+vn 0.321600 0.517100 0.793200
+vn 0.202200 0.325100 0.923800
+vn 0.069000 0.110900 0.991400
+vn -0.069000 -0.110900 0.991400
+vn -0.202200 -0.325100 0.923800
+vn -0.321600 -0.517100 0.793200
+vn -0.419000 -0.673900 0.608600
+vn -0.487900 -0.784600 0.382500
+vn -0.523600 -0.841900 0.130500
+vn -0.523600 -0.841900 -0.130500
+vn -0.487900 -0.784600 -0.382500
+vn -0.419000 -0.673900 -0.608600
+vn -0.321600 -0.517100 -0.793200
+vn -0.202200 -0.325100 -0.923800
+vn -0.069000 -0.110900 -0.991400
+vn 0.069000 0.110900 -0.991400
+vn 0.202200 0.325100 -0.923800
+vn 0.321600 0.517100 -0.793200
+vn 0.419000 0.673900 -0.608600
+vn 0.487900 0.784600 -0.382500
+vn 0.523600 0.841900 -0.130500
+vn 0.467400 0.874400 0.130500
+vn 0.435500 0.814900 0.382500
+vn 0.374100 0.699800 0.608600
+vn 0.287100 0.537100 0.793200
+vn 0.180500 0.337700 0.923800
+vn 0.061600 0.115200 0.991400
+vn -0.061600 -0.115200 0.991400
+vn -0.180500 -0.337700 0.923800
+vn -0.287100 -0.537100 0.793200
+vn -0.374100 -0.699800 0.608600
+vn -0.435500 -0.814900 0.382500
+vn -0.467400 -0.874400 0.130500
+vn -0.467400 -0.874400 -0.130500
+vn -0.435500 -0.814900 -0.382500
+vn -0.374100 -0.699800 -0.608600
+vn -0.287100 -0.537100 -0.793200
+vn -0.180500 -0.337700 -0.923800
+vn -0.061600 -0.115200 -0.991400
+vn 0.061600 0.115200 -0.991400
+vn 0.180500 0.337700 -0.923800
+vn 0.287100 0.537100 -0.793200
+vn 0.374100 0.699800 -0.608600
+vn 0.435500 0.814900 -0.382500
+vn 0.467400 0.874400 -0.130500
+vn 0.409200 0.903100 0.130500
+vn 0.381300 0.841600 0.382500
+vn 0.327500 0.722800 0.608600
+vn 0.251300 0.554700 0.793200
+vn 0.158000 0.348700 0.923800
+vn 0.053900 0.119000 0.991400
+vn -0.053900 -0.119000 0.991400
+vn -0.158000 -0.348700 0.923800
+vn -0.251300 -0.554700 0.793200
+vn -0.327500 -0.722800 0.608600
+vn -0.381300 -0.841600 0.382500
+vn -0.409200 -0.903100 0.130500
+vn -0.409200 -0.903100 -0.130500
+vn -0.381300 -0.841600 -0.382500
+vn -0.327500 -0.722800 -0.608600
+vn -0.251300 -0.554700 -0.793200
+vn -0.158000 -0.348700 -0.923800
+vn -0.053900 -0.119000 -0.991400
+vn 0.053900 0.119000 -0.991400
+vn 0.158000 0.348700 -0.923800
+vn 0.251300 0.554700 -0.793200
+vn 0.327500 0.722800 -0.608600
+vn 0.381300 0.841600 -0.382500
+vn 0.409200 0.903100 -0.130500
+vn 0.349200 0.927900 0.130500
+vn 0.325500 0.864700 0.382500
+vn 0.279500 0.742600 0.608600
+vn 0.214500 0.569900 0.793200
+vn 0.134900 0.358300 0.923800
+vn 0.046000 0.122200 0.991400
+vn -0.046000 -0.122200 0.991400
+vn -0.134900 -0.358300 0.923800
+vn -0.214500 -0.569900 0.793200
+vn -0.279500 -0.742700 0.608600
+vn -0.325500 -0.864700 0.382500
+vn -0.349200 -0.927900 0.130500
+vn -0.349200 -0.927900 -0.130500
+vn -0.325500 -0.864700 -0.382500
+vn -0.279500 -0.742700 -0.608600
+vn -0.214500 -0.569900 -0.793200
+vn -0.134900 -0.358300 -0.923800
+vn -0.046000 -0.122200 -0.991400
+vn 0.046000 0.122200 -0.991400
+vn 0.134900 0.358300 -0.923800
+vn 0.214500 0.569900 -0.793200
+vn 0.279500 0.742600 -0.608600
+vn 0.325500 0.864700 -0.382500
+vn 0.349200 0.927900 -0.130500
+vn 0.287800 0.948800 0.130500
+vn 0.268200 0.884200 0.382500
+vn 0.230300 0.759300 0.608600
+vn 0.176800 0.582700 0.793200
+vn 0.111100 0.366400 0.923800
+vn 0.037900 0.125000 0.991400
+vn -0.037900 -0.125000 0.991400
+vn -0.111100 -0.366400 0.923800
+vn -0.176800 -0.582700 0.793200
+vn -0.230300 -0.759300 0.608600
+vn -0.268200 -0.884200 0.382500
+vn -0.287800 -0.948800 0.130500
+vn -0.287800 -0.948800 -0.130500
+vn -0.268200 -0.884200 -0.382500
+vn -0.230300 -0.759300 -0.608600
+vn -0.176800 -0.582700 -0.793200
+vn -0.111100 -0.366400 -0.923800
+vn -0.037900 -0.125000 -0.991400
+vn 0.037900 0.125000 -0.991400
+vn 0.111100 0.366400 -0.923800
+vn 0.176800 0.582700 -0.793200
+vn 0.230300 0.759300 -0.608600
+vn 0.268200 0.884200 -0.382500
+vn 0.287800 0.948800 -0.130500
+vn 0.225100 0.965600 0.130500
+vn 0.209800 0.899800 0.382500
+vn 0.180200 0.772800 0.608600
+vn 0.138300 0.593100 0.793200
+vn 0.086900 0.372900 0.923800
+vn 0.029700 0.127200 0.991400
+vn -0.029700 -0.127200 0.991400
+vn -0.086900 -0.372900 0.923800
+vn -0.138300 -0.593100 0.793200
+vn -0.180200 -0.772800 0.608600
+vn -0.209800 -0.899800 0.382500
+vn -0.225100 -0.965600 0.130500
+vn -0.225100 -0.965600 -0.130500
+vn -0.209800 -0.899800 -0.382500
+vn -0.180200 -0.772800 -0.608600
+vn -0.138300 -0.593100 -0.793200
+vn -0.086900 -0.372900 -0.923800
+vn -0.029700 -0.127200 -0.991400
+vn 0.029700 0.127200 -0.991400
+vn 0.086900 0.372900 -0.923800
+vn 0.138300 0.593100 -0.793200
+vn 0.180200 0.772800 -0.608600
+vn 0.209800 0.899800 -0.382500
+vn 0.225100 0.965600 -0.130500
+vn 0.161500 0.978200 0.130500
+vn 0.150500 0.911600 0.382500
+vn 0.129300 0.782900 0.608600
+vn 0.099200 0.600800 0.793200
+vn 0.062400 0.377700 0.923800
+vn 0.021300 0.128900 0.991400
+vn -0.021300 -0.128900 0.991400
+vn -0.062400 -0.377700 0.923800
+vn -0.099200 -0.600800 0.793200
+vn -0.129300 -0.782900 0.608600
+vn -0.150500 -0.911600 0.382500
+vn -0.161500 -0.978200 0.130500
+vn -0.161500 -0.978200 -0.130500
+vn -0.150500 -0.911600 -0.382500
+vn -0.129300 -0.782900 -0.608600
+vn -0.099200 -0.600800 -0.793200
+vn -0.062400 -0.377700 -0.923800
+vn -0.021300 -0.128900 -0.991400
+vn 0.021300 0.128900 -0.991400
+vn 0.062400 0.377700 -0.923800
+vn 0.099200 0.600800 -0.793200
+vn 0.129300 0.782900 -0.608600
+vn 0.150500 0.911600 -0.382500
+vn 0.161500 0.978200 -0.130500
+vn 0.097200 0.986700 0.130500
+vn 0.090600 0.919500 0.382500
+vn 0.077800 0.789700 0.608600
+vn 0.059700 0.606000 0.793200
+vn 0.037500 0.381000 0.923800
+vn 0.012800 0.130000 0.991400
+vn -0.012800 -0.130000 0.991400
+vn -0.037500 -0.381000 0.923800
+vn -0.059700 -0.606000 0.793200
+vn -0.077800 -0.789700 0.608600
+vn -0.090600 -0.919500 0.382500
+vn -0.097200 -0.986700 0.130500
+vn -0.097200 -0.986700 -0.130500
+vn -0.090600 -0.919500 -0.382500
+vn -0.077800 -0.789700 -0.608600
+vn -0.059700 -0.606000 -0.793200
+vn -0.037500 -0.381000 -0.923800
+vn -0.012800 -0.130000 -0.991400
+vn 0.012800 0.130000 -0.991400
+vn 0.037500 0.381000 -0.923800
+vn 0.059700 0.606000 -0.793200
+vn 0.077800 0.789700 -0.608600
+vn 0.090600 0.919500 -0.382500
+vn 0.097200 0.986700 -0.130500
+vn 0.032400 0.990900 0.130500
+vn 0.030200 0.923500 0.382500
+vn 0.026000 0.793100 0.608600
+vn 0.019900 0.608600 0.793200
+vn 0.012500 0.382700 0.923800
+vn 0.004300 0.130500 0.991400
+vn -0.004300 -0.130500 0.991400
+vn -0.012500 -0.382700 0.923800
+vn -0.019900 -0.608600 0.793200
+vn -0.026000 -0.793100 0.608600
+vn -0.030200 -0.923500 0.382500
+vn -0.032400 -0.990900 0.130500
+vn -0.032400 -0.990900 -0.130500
+vn -0.030200 -0.923500 -0.382500
+vn -0.026000 -0.793100 -0.608600
+vn -0.019900 -0.608600 -0.793200
+vn -0.012500 -0.382700 -0.923800
+vn -0.004300 -0.130500 -0.991400
+vn 0.004300 0.130500 -0.991400
+vn 0.012500 0.382700 -0.923800
+vn 0.019900 0.608600 -0.793200
+vn 0.026000 0.793100 -0.608600
+vn 0.030200 0.923500 -0.382500
+vn 0.032400 0.990900 -0.130500
+vn -0.032400 0.990900 0.130500
+vn -0.030200 0.923500 0.382500
+vn -0.026000 0.793100 0.608600
+vn -0.019900 0.608600 0.793200
+vn -0.012500 0.382700 0.923800
+vn -0.004300 0.130500 0.991400
+vn 0.004300 -0.130500 0.991400
+vn 0.012500 -0.382700 0.923800
+vn 0.019900 -0.608600 0.793200
+vn 0.026000 -0.793100 0.608600
+vn 0.030200 -0.923500 0.382500
+vn 0.032400 -0.990900 0.130500
+vn 0.032400 -0.990900 -0.130500
+vn 0.030200 -0.923500 -0.382500
+vn 0.026000 -0.793100 -0.608600
+vn 0.019900 -0.608600 -0.793200
+vn 0.012500 -0.382700 -0.923800
+vn 0.004300 -0.130500 -0.991400
+vn -0.004300 0.130500 -0.991400
+vn -0.012500 0.382700 -0.923800
+vn -0.019900 0.608600 -0.793200
+vn -0.026000 0.793100 -0.608600
+vn -0.030200 0.923500 -0.382500
+vn -0.032400 0.990900 -0.130500
+vn -0.097200 0.986700 0.130500
+vn -0.090600 0.919500 0.382500
+vn -0.077800 0.789700 0.608600
+vn -0.059700 0.606000 0.793200
+vn -0.037500 0.381000 0.923800
+vn -0.012800 0.130000 0.991400
+vn 0.012800 -0.130000 0.991400
+vn 0.037500 -0.381000 0.923800
+vn 0.059700 -0.606000 0.793200
+vn 0.077800 -0.789700 0.608600
+vn 0.090600 -0.919500 0.382500
+vn 0.097200 -0.986700 0.130500
+vn 0.097200 -0.986700 -0.130500
+vn 0.090600 -0.919500 -0.382500
+vn 0.077800 -0.789700 -0.608600
+vn 0.059700 -0.606000 -0.793200
+vn 0.037500 -0.381000 -0.923800
+vn 0.012800 -0.130000 -0.991400
+vn -0.012800 0.130000 -0.991400
+vn -0.037500 0.381000 -0.923800
+vn -0.059700 0.606000 -0.793200
+vn -0.077800 0.789700 -0.608600
+vn -0.090600 0.919500 -0.382500
+vn -0.097200 0.986700 -0.130500
+vn -0.161500 0.978200 0.130500
+vn -0.150500 0.911600 0.382500
+vn -0.129300 0.782900 0.608600
+vn -0.099200 0.600800 0.793200
+vn -0.062400 0.377700 0.923800
+vn -0.021300 0.128900 0.991400
+vn 0.021300 -0.128800 0.991400
+vn 0.062400 -0.377700 0.923800
+vn 0.099200 -0.600800 0.793200
+vn 0.129300 -0.782900 0.608600
+vn 0.150500 -0.911600 0.382500
+vn 0.161500 -0.978200 0.130500
+vn 0.161500 -0.978200 -0.130500
+vn 0.150500 -0.911600 -0.382500
+vn 0.129300 -0.782900 -0.608600
+vn 0.099200 -0.600800 -0.793200
+vn 0.062400 -0.377700 -0.923800
+vn 0.021300 -0.128900 -0.991400
+vn -0.021300 0.128900 -0.991400
+vn -0.062400 0.377700 -0.923800
+vn -0.099200 0.600800 -0.793200
+vn -0.129300 0.782900 -0.608600
+vn -0.150500 0.911600 -0.382500
+vn -0.161500 0.978200 -0.130500
+vn -0.225100 0.965600 0.130500
+vn -0.209800 0.899800 0.382500
+vn -0.180200 0.772800 0.608600
+vn -0.138300 0.593100 0.793200
+vn -0.086900 0.372900 0.923800
+vn -0.029700 0.127200 0.991400
+vn 0.029700 -0.127200 0.991400
+vn 0.086900 -0.372900 0.923800
+vn 0.138300 -0.593100 0.793200
+vn 0.180200 -0.772800 0.608600
+vn 0.209800 -0.899800 0.382500
+vn 0.225100 -0.965600 0.130500
+vn 0.225100 -0.965600 -0.130500
+vn 0.209800 -0.899800 -0.382500
+vn 0.180200 -0.772800 -0.608600
+vn 0.138300 -0.593100 -0.793200
+vn 0.086900 -0.372900 -0.923800
+vn 0.029700 -0.127200 -0.991400
+vn -0.029700 0.127200 -0.991400
+vn -0.086900 0.372900 -0.923800
+vn -0.138300 0.593100 -0.793200
+vn -0.180200 0.772800 -0.608600
+vn -0.209800 0.899800 -0.382500
+vn -0.225100 0.965600 -0.130500
+vn -0.287800 0.948800 0.130500
+vn -0.268200 0.884200 0.382500
+vn -0.230300 0.759300 0.608600
+vn -0.176800 0.582700 0.793200
+vn -0.111100 0.366400 0.923800
+vn -0.037900 0.125000 0.991400
+vn 0.037900 -0.125000 0.991400
+vn 0.111100 -0.366400 0.923800
+vn 0.176800 -0.582700 0.793200
+vn 0.230300 -0.759300 0.608600
+vn 0.268200 -0.884200 0.382500
+vn 0.287800 -0.948800 0.130500
+vn 0.287800 -0.948800 -0.130500
+vn 0.268200 -0.884200 -0.382500
+vn 0.230300 -0.759300 -0.608600
+vn 0.176800 -0.582700 -0.793200
+vn 0.111100 -0.366400 -0.923800
+vn 0.037900 -0.125000 -0.991400
+vn -0.037900 0.125000 -0.991400
+vn -0.111100 0.366400 -0.923800
+vn -0.176800 0.582700 -0.793200
+vn -0.230300 0.759300 -0.608600
+vn -0.268200 0.884200 -0.382500
+vn -0.287800 0.948800 -0.130500
+vn -0.349200 0.927900 0.130500
+vn -0.325500 0.864700 0.382500
+vn -0.279500 0.742600 0.608600
+vn -0.214500 0.569900 0.793200
+vn -0.134900 0.358300 0.923800
+vn -0.046000 0.122200 0.991400
+vn 0.046000 -0.122200 0.991400
+vn 0.134900 -0.358300 0.923800
+vn 0.214500 -0.569900 0.793200
+vn 0.279500 -0.742700 0.608600
+vn 0.325500 -0.864700 0.382500
+vn 0.349200 -0.927900 0.130500
+vn 0.349200 -0.927900 -0.130500
+vn 0.325500 -0.864700 -0.382500
+vn 0.279500 -0.742700 -0.608600
+vn 0.214500 -0.569900 -0.793200
+vn 0.134900 -0.358300 -0.923800
+vn 0.046000 -0.122200 -0.991400
+vn -0.046000 0.122200 -0.991400
+vn -0.134900 0.358300 -0.923800
+vn -0.214500 0.569900 -0.793200
+vn -0.279500 0.742600 -0.608600
+vn -0.325500 0.864700 -0.382500
+vn -0.349200 0.927900 -0.130500
+vn -0.409200 0.903100 0.130500
+vn -0.381300 0.841600 0.382500
+vn -0.327500 0.722800 0.608600
+vn -0.251300 0.554700 0.793200
+vn -0.158000 0.348700 0.923800
+vn -0.053900 0.119000 0.991400
+vn 0.053900 -0.119000 0.991400
+vn 0.158000 -0.348700 0.923800
+vn 0.251300 -0.554700 0.793200
+vn 0.327500 -0.722800 0.608600
+vn 0.381300 -0.841600 0.382500
+vn 0.409200 -0.903100 0.130500
+vn 0.409200 -0.903100 -0.130500
+vn 0.381300 -0.841600 -0.382500
+vn 0.327500 -0.722800 -0.608600
+vn 0.251300 -0.554700 -0.793200
+vn 0.158000 -0.348700 -0.923800
+vn 0.053900 -0.119000 -0.991400
+vn -0.053900 0.119000 -0.991400
+vn -0.158000 0.348700 -0.923800
+vn -0.251300 0.554700 -0.793200
+vn -0.327500 0.722800 -0.608600
+vn -0.381300 0.841600 -0.382500
+vn -0.409200 0.903100 -0.130500
+vn -0.467400 0.874400 0.130500
+vn -0.435500 0.814900 0.382500
+vn -0.374100 0.699800 0.608600
+vn -0.287100 0.537100 0.793200
+vn -0.180500 0.337700 0.923800
+vn -0.061600 0.115200 0.991400
+vn 0.061600 -0.115200 0.991400
+vn 0.180500 -0.337700 0.923800
+vn 0.287100 -0.537100 0.793200
+vn 0.374100 -0.699800 0.608600
+vn 0.435500 -0.814900 0.382500
+vn 0.467400 -0.874400 0.130500
+vn 0.467400 -0.874400 -0.130500
+vn 0.435500 -0.814900 -0.382500
+vn 0.374100 -0.699800 -0.608600
+vn 0.287100 -0.537100 -0.793200
+vn 0.180500 -0.337700 -0.923800
+vn 0.061600 -0.115200 -0.991400
+vn -0.061600 0.115200 -0.991400
+vn -0.180500 0.337700 -0.923800
+vn -0.287100 0.537100 -0.793200
+vn -0.374100 0.699800 -0.608600
+vn -0.435500 0.814900 -0.382500
+vn -0.467400 0.874400 -0.130500
+vn -0.523600 0.841900 0.130500
+vn -0.487900 0.784600 0.382500
+vn -0.419000 0.673900 0.608600
+vn -0.321600 0.517100 0.793200
+vn -0.202200 0.325100 0.923800
+vn -0.069000 0.110900 0.991400
+vn 0.069000 -0.110900 0.991400
+vn 0.202200 -0.325100 0.923800
+vn 0.321600 -0.517100 0.793200
+vn 0.419000 -0.673900 0.608600
+vn 0.487900 -0.784600 0.382500
+vn 0.523600 -0.841900 0.130500
+vn 0.523600 -0.841900 -0.130500
+vn 0.487900 -0.784600 -0.382500
+vn 0.419000 -0.673900 -0.608600
+vn 0.321600 -0.517100 -0.793200
+vn 0.202200 -0.325100 -0.923800
+vn 0.069000 -0.110900 -0.991400
+vn -0.069000 0.110900 -0.991400
+vn -0.202200 0.325100 -0.923800
+vn -0.321600 0.517100 -0.793200
+vn -0.419000 0.673900 -0.608600
+vn -0.487900 0.784600 -0.382500
+vn -0.523600 0.841900 -0.130500
+vn -0.577500 0.805900 0.130500
+vn -0.538200 0.751000 0.382500
+vn -0.462200 0.645000 0.608600
+vn -0.354700 0.495000 0.793200
+vn -0.223000 0.311200 0.923800
+vn -0.076100 0.106200 0.991400
+vn 0.076100 -0.106200 0.991400
+vn 0.223000 -0.311200 0.923800
+vn 0.354700 -0.495000 0.793200
+vn 0.462200 -0.645000 0.608600
+vn 0.538200 -0.751000 0.382500
+vn 0.577500 -0.805900 0.130500
+vn 0.577500 -0.805900 -0.130500
+vn 0.538200 -0.751000 -0.382500
+vn 0.462200 -0.645000 -0.608600
+vn 0.354700 -0.495000 -0.793200
+vn 0.223000 -0.311200 -0.923800
+vn 0.076100 -0.106200 -0.991400
+vn -0.076100 0.106200 -0.991400
+vn -0.223000 0.311200 -0.923800
+vn -0.354700 0.495000 -0.793200
+vn -0.462200 0.645000 -0.608600
+vn -0.538200 0.751000 -0.382500
+vn -0.577500 0.805900 -0.130500
+vn -0.629000 0.766400 0.130500
+vn -0.586100 0.714200 0.382500
+vn -0.503400 0.613400 0.608600
+vn -0.386300 0.470700 0.793200
+vn -0.242900 0.296000 0.923800
+vn -0.082800 0.101000 0.991400
+vn 0.082800 -0.101000 0.991400
+vn 0.242900 -0.296000 0.923800
+vn 0.386300 -0.470700 0.793200
+vn 0.503400 -0.613400 0.608600
+vn 0.586100 -0.714200 0.382500
+vn 0.629000 -0.766400 0.130500
+vn 0.629000 -0.766400 -0.130500
+vn 0.586100 -0.714200 -0.382500
+vn 0.503400 -0.613400 -0.608600
+vn 0.386300 -0.470700 -0.793200
+vn 0.242900 -0.296000 -0.923800
+vn 0.082800 -0.101000 -0.991400
+vn -0.082800 0.101000 -0.991400
+vn -0.242900 0.296000 -0.923800
+vn -0.386300 0.470700 -0.793200
+vn -0.503400 0.613400 -0.608600
+vn -0.586100 0.714200 -0.382500
+vn -0.629000 0.766400 -0.130500
+vn -0.677800 0.723600 0.130500
+vn -0.631600 0.674400 0.382500
+vn -0.542400 0.579200 0.608600
+vn -0.416300 0.444500 0.793200
+vn -0.261700 0.279400 0.923800
+vn -0.089300 0.095300 0.991400
+vn 0.089300 -0.095300 0.991400
+vn 0.261700 -0.279400 0.923800
+vn 0.416300 -0.444500 0.793200
+vn 0.542400 -0.579200 0.608600
+vn 0.631600 -0.674400 0.382500
+vn 0.677800 -0.723600 0.130500
+vn 0.677800 -0.723600 -0.130500
+vn 0.631600 -0.674400 -0.382500
+vn 0.542400 -0.579200 -0.608600
+vn 0.416300 -0.444500 -0.793200
+vn 0.261700 -0.279400 -0.923800
+vn 0.089300 -0.095300 -0.991400
+vn -0.089300 0.095300 -0.991400
+vn -0.261700 0.279400 -0.923800
+vn -0.416300 0.444500 -0.793200
+vn -0.542400 0.579200 -0.608600
+vn -0.631600 0.674400 -0.382500
+vn -0.677800 0.723600 -0.130500
+vn -0.723600 0.677800 0.130500
+vn -0.674400 0.631600 0.382500
+vn -0.579200 0.542400 0.608600
+vn -0.444500 0.416300 0.793200
+vn -0.279400 0.261700 0.923800
+vn -0.095300 0.089300 0.991400
+vn 0.095300 -0.089300 0.991400
+vn 0.279400 -0.261700 0.923800
+vn 0.444500 -0.416300 0.793200
+vn 0.579200 -0.542400 0.608600
+vn 0.674400 -0.631600 0.382500
+vn 0.723600 -0.677800 0.130500
+vn 0.723600 -0.677800 -0.130500
+vn 0.674400 -0.631600 -0.382500
+vn 0.579200 -0.542400 -0.608600
+vn 0.444500 -0.416300 -0.793200
+vn 0.279400 -0.261700 -0.923800
+vn 0.095300 -0.089300 -0.991400
+vn -0.095300 0.089300 -0.991400
+vn -0.279400 0.261700 -0.923800
+vn -0.444500 0.416300 -0.793200
+vn -0.579200 0.542400 -0.608600
+vn -0.674400 0.631600 -0.382500
+vn -0.723600 0.677700 -0.130500
+vn -0.766400 0.629000 0.130500
+vn -0.714200 0.586100 0.382500
+vn -0.613400 0.503400 0.608600
+vn -0.470700 0.386300 0.793200
+vn -0.296000 0.242900 0.923800
+vn -0.101000 0.082800 0.991400
+vn 0.101000 -0.082800 0.991400
+vn 0.296000 -0.242900 0.923800
+vn 0.470700 -0.386300 0.793200
+vn 0.613400 -0.503400 0.608600
+vn 0.714200 -0.586200 0.382500
+vn 0.766400 -0.629000 0.130500
+vn 0.766400 -0.629000 -0.130500
+vn 0.714200 -0.586100 -0.382500
+vn 0.613400 -0.503400 -0.608600
+vn 0.470700 -0.386300 -0.793200
+vn 0.296000 -0.242900 -0.923800
+vn 0.101000 -0.082800 -0.991400
+vn -0.101000 0.082800 -0.991400
+vn -0.296000 0.242900 -0.923800
+vn -0.470700 0.386300 -0.793200
+vn -0.613400 0.503400 -0.608600
+vn -0.714200 0.586100 -0.382500
+vn -0.766400 0.629000 -0.130500
+vn -0.805900 0.577500 0.130500
+vn -0.751000 0.538200 0.382500
+vn -0.645000 0.462200 0.608600
+vn -0.495000 0.354700 0.793200
+vn -0.311200 0.223000 0.923800
+vn -0.106200 0.076100 0.991400
+vn 0.106200 -0.076100 0.991400
+vn 0.311200 -0.223000 0.923800
+vn 0.495000 -0.354700 0.793200
+vn 0.645000 -0.462200 0.608600
+vn 0.751000 -0.538200 0.382500
+vn 0.805900 -0.577500 0.130500
+vn 0.805900 -0.577500 -0.130500
+vn 0.751000 -0.538200 -0.382500
+vn 0.645000 -0.462200 -0.608600
+vn 0.495000 -0.354700 -0.793200
+vn 0.311200 -0.223000 -0.923800
+vn 0.106200 -0.076100 -0.991400
+vn -0.106200 0.076100 -0.991400
+vn -0.311200 0.223000 -0.923800
+vn -0.495000 0.354700 -0.793200
+vn -0.645000 0.462200 -0.608600
+vn -0.751000 0.538200 -0.382500
+vn -0.805900 0.577500 -0.130500
+vn -0.841900 0.523600 0.130500
+vn -0.784600 0.487900 0.382500
+vn -0.673800 0.419000 0.608600
+vn -0.517100 0.321600 0.793200
+vn -0.325100 0.202200 0.923800
+vn -0.110900 0.069000 0.991400
+vn 0.110900 -0.069000 0.991400
+vn 0.325100 -0.202200 0.923800
+vn 0.517100 -0.321600 0.793200
+vn 0.673800 -0.419000 0.608600
+vn 0.784600 -0.487900 0.382500
+vn 0.841900 -0.523600 0.130500
+vn 0.841900 -0.523600 -0.130500
+vn 0.784600 -0.487900 -0.382500
+vn 0.673800 -0.419000 -0.608600
+vn 0.517100 -0.321600 -0.793200
+vn 0.325100 -0.202200 -0.923800
+vn 0.110900 -0.069000 -0.991400
+vn -0.110900 0.069000 -0.991400
+vn -0.325100 0.202200 -0.923800
+vn -0.517100 0.321600 -0.793200
+vn -0.673900 0.419000 -0.608600
+vn -0.784600 0.487900 -0.382500
+vn -0.841900 0.523600 -0.130500
+vn -0.874400 0.467400 0.130500
+vn -0.814900 0.435500 0.382500
+vn -0.699800 0.374100 0.608600
+vn -0.537100 0.287100 0.793200
+vn -0.337700 0.180500 0.923800
+vn -0.115200 0.061600 0.991400
+vn 0.115200 -0.061600 0.991400
+vn 0.337700 -0.180500 0.923800
+vn 0.537100 -0.287100 0.793200
+vn 0.699800 -0.374100 0.608600
+vn 0.814900 -0.435500 0.382500
+vn 0.874400 -0.467400 0.130500
+vn 0.874400 -0.467400 -0.130500
+vn 0.814900 -0.435500 -0.382500
+vn 0.699800 -0.374100 -0.608600
+vn 0.537100 -0.287100 -0.793200
+vn 0.337700 -0.180500 -0.923800
+vn 0.115200 -0.061600 -0.991400
+vn -0.115200 0.061600 -0.991400
+vn -0.337700 0.180500 -0.923800
+vn -0.537100 0.287100 -0.793200
+vn -0.699800 0.374100 -0.608600
+vn -0.814900 0.435500 -0.382500
+vn -0.874400 0.467400 -0.130500
+vn -0.903100 0.409200 0.130500
+vn -0.841600 0.381300 0.382500
+vn -0.722800 0.327500 0.608600
+vn -0.554700 0.251300 0.793200
+vn -0.348700 0.158000 0.923800
+vn -0.119000 0.053900 0.991400
+vn 0.119000 -0.053900 0.991400
+vn 0.348700 -0.158000 0.923800
+vn 0.554700 -0.251300 0.793200
+vn 0.722800 -0.327500 0.608600
+vn 0.841600 -0.381300 0.382500
+vn 0.903100 -0.409200 0.130500
+vn 0.903100 -0.409200 -0.130500
+vn 0.841600 -0.381300 -0.382500
+vn 0.722800 -0.327500 -0.608600
+vn 0.554700 -0.251300 -0.793200
+vn 0.348700 -0.158000 -0.923800
+vn 0.119000 -0.053900 -0.991400
+vn -0.119000 0.053900 -0.991400
+vn -0.348700 0.158000 -0.923800
+vn -0.554700 0.251300 -0.793200
+vn -0.722800 0.327500 -0.608600
+vn -0.841600 0.381300 -0.382500
+vn -0.903100 0.409200 -0.130500
+vn -0.927900 0.349200 0.130500
+vn -0.864700 0.325500 0.382500
+vn -0.742600 0.279500 0.608600
+vn -0.569900 0.214500 0.793200
+vn -0.358300 0.134900 0.923800
+vn -0.122200 0.046000 0.991400
+vn 0.122200 -0.046000 0.991400
+vn 0.358300 -0.134900 0.923800
+vn 0.569900 -0.214500 0.793200
+vn 0.742700 -0.279500 0.608600
+vn 0.864700 -0.325500 0.382500
+vn 0.927900 -0.349200 0.130500
+vn 0.927900 -0.349200 -0.130500
+vn 0.864700 -0.325500 -0.382500
+vn 0.742700 -0.279500 -0.608600
+vn 0.569900 -0.214500 -0.793200
+vn 0.358300 -0.134900 -0.923800
+vn 0.122200 -0.046000 -0.991400
+vn -0.122200 0.046000 -0.991400
+vn -0.358300 0.134900 -0.923800
+vn -0.569900 0.214500 -0.793200
+vn -0.742600 0.279500 -0.608600
+vn -0.864700 0.325500 -0.382500
+vn -0.927900 0.349200 -0.130500
+vn -0.948800 0.287800 0.130500
+vn -0.884200 0.268200 0.382500
+vn -0.759300 0.230300 0.608600
+vn -0.582700 0.176800 0.793200
+vn -0.366400 0.111100 0.923800
+vn -0.125000 0.037900 0.991400
+vn 0.125000 -0.037900 0.991400
+vn 0.366400 -0.111100 0.923800
+vn 0.582700 -0.176800 0.793200
+vn 0.759300 -0.230300 0.608600
+vn 0.884200 -0.268200 0.382500
+vn 0.948800 -0.287800 0.130500
+vn 0.948800 -0.287800 -0.130500
+vn 0.884200 -0.268200 -0.382500
+vn 0.759300 -0.230300 -0.608600
+vn 0.582700 -0.176800 -0.793200
+vn 0.366400 -0.111100 -0.923800
+vn 0.125000 -0.037900 -0.991400
+vn -0.125000 0.037900 -0.991400
+vn -0.366400 0.111100 -0.923800
+vn -0.582700 0.176800 -0.793200
+vn -0.759300 0.230300 -0.608600
+vn -0.884200 0.268200 -0.382500
+vn -0.948800 0.287800 -0.130500
+vn -0.965600 0.225100 0.130500
+vn -0.899800 0.209800 0.382500
+vn -0.772800 0.180200 0.608600
+vn -0.593100 0.138300 0.793200
+vn -0.372900 0.086900 0.923800
+vn -0.127200 0.029700 0.991400
+vn 0.127200 -0.029700 0.991400
+vn 0.372900 -0.086900 0.923800
+vn 0.593100 -0.138300 0.793200
+vn 0.772800 -0.180200 0.608600
+vn 0.899800 -0.209800 0.382500
+vn 0.965600 -0.225100 0.130500
+vn 0.965600 -0.225100 -0.130500
+vn 0.899800 -0.209800 -0.382500
+vn 0.772800 -0.180200 -0.608600
+vn 0.593100 -0.138300 -0.793200
+vn 0.372900 -0.086900 -0.923800
+vn 0.127200 -0.029700 -0.991400
+vn -0.127200 0.029700 -0.991400
+vn -0.372900 0.086900 -0.923800
+vn -0.593100 0.138300 -0.793200
+vn -0.772800 0.180200 -0.608600
+vn -0.899800 0.209800 -0.382500
+vn -0.965600 0.225100 -0.130500
+vn -0.978200 0.161500 0.130500
+vn -0.911600 0.150500 0.382500
+vn -0.782900 0.129300 0.608600
+vn -0.600800 0.099200 0.793200
+vn -0.377700 0.062400 0.923800
+vn -0.128900 0.021300 0.991400
+vn 0.128900 -0.021300 0.991400
+vn 0.377700 -0.062400 0.923800
+vn 0.600800 -0.099200 0.793200
+vn 0.782900 -0.129300 0.608600
+vn 0.911600 -0.150500 0.382500
+vn 0.978200 -0.161500 0.130500
+vn 0.978200 -0.161500 -0.130500
+vn 0.911600 -0.150500 -0.382500
+vn 0.782900 -0.129300 -0.608600
+vn 0.600800 -0.099200 -0.793200
+vn 0.377700 -0.062400 -0.923800
+vn 0.128900 -0.021300 -0.991400
+vn -0.128900 0.021300 -0.991400
+vn -0.377700 0.062400 -0.923800
+vn -0.600800 0.099200 -0.793200
+vn -0.782900 0.129300 -0.608600
+vn -0.911600 0.150500 -0.382500
+vn -0.978200 0.161500 -0.130500
+vn -0.986700 0.097200 0.130500
+vn -0.919500 0.090600 0.382500
+vn -0.789700 0.077800 0.608600
+vn -0.606000 0.059700 0.793200
+vn -0.381000 0.037500 0.923800
+vn -0.130000 0.012800 0.991400
+vn 0.130000 -0.012800 0.991400
+vn 0.381000 -0.037500 0.923800
+vn 0.606000 -0.059700 0.793200
+vn 0.789700 -0.077800 0.608600
+vn 0.919500 -0.090600 0.382500
+vn 0.986700 -0.097200 0.130500
+vn 0.986700 -0.097200 -0.130500
+vn 0.919500 -0.090600 -0.382500
+vn 0.789700 -0.077800 -0.608600
+vn 0.606000 -0.059700 -0.793200
+vn 0.381000 -0.037500 -0.923800
+vn 0.130000 -0.012800 -0.991400
+vn -0.130000 0.012800 -0.991400
+vn -0.381000 0.037500 -0.923800
+vn -0.606000 0.059700 -0.793200
+vn -0.789700 0.077800 -0.608600
+vn -0.919500 0.090600 -0.382500
+vn -0.986700 0.097200 -0.130500
+vn -0.990900 0.032400 0.130500
+vn -0.923500 0.030200 0.382500
+vn -0.793100 0.026000 0.608600
+vn -0.608600 0.019900 0.793200
+vn -0.382700 0.012500 0.923800
+vn -0.130500 0.004300 0.991400
+vn 0.130500 -0.004300 0.991400
+vn 0.382700 -0.012500 0.923800
+vn 0.608600 -0.019900 0.793200
+vn 0.793100 -0.026000 0.608600
+vn 0.923500 -0.030200 0.382500
+vn 0.990900 -0.032400 0.130500
+vn 0.990900 -0.032400 -0.130500
+vn 0.923500 -0.030200 -0.382500
+vn 0.793100 -0.026000 -0.608600
+vn 0.608600 -0.019900 -0.793200
+vn 0.382700 -0.012500 -0.923800
+vn 0.130500 -0.004300 -0.991400
+vn -0.130500 0.004300 -0.991400
+vn -0.382700 0.012500 -0.923800
+vn -0.608600 0.019900 -0.793200
+vn -0.793100 0.026000 -0.608600
+vn -0.923500 0.030200 -0.382500
+vn -0.990900 0.032400 -0.130500
+vn -0.128800 -0.021300 0.991400
+vn 0.128800 0.021300 0.991400
+vn 0.814900 0.435500 0.382500
+vn 0.673900 0.419000 0.608600
+vn 0.673900 0.419000 -0.608600
+vn -0.723600 -0.677800 0.130500
+vn 0.723600 0.677700 0.130500
+vn 0.723600 0.677700 -0.130500
+vn -0.629000 -0.766400 0.130400
+vn -0.586200 -0.714200 0.382500
+vn 0.586200 0.714200 0.382500
+vn 0.586200 0.714200 -0.382500
+vn -0.586200 -0.714200 -0.382500
+vn -0.629000 -0.766400 -0.130400
+vn 0.419000 0.673900 0.608600
+vn 0.279500 0.742700 0.608600
+vn 0.279500 0.742700 -0.608600
+vn -0.032400 -0.990900 0.130400
+vn -0.032400 -0.990900 -0.130400
+vn 0.021300 -0.128900 0.991400
+vn 0.279500 -0.742600 0.608600
+vn -0.279500 0.742700 0.608600
+vn -0.279500 0.742700 -0.608600
+vn 0.279500 -0.742600 -0.608600
+vn -0.180500 0.337600 0.923800
+vn -0.180500 0.337600 -0.923800
+vn 0.419000 -0.673800 0.608600
+vn 0.419000 -0.673800 -0.608600
+vn 0.586200 -0.714200 0.382500
+vn 0.586200 -0.714200 -0.382500
+vn 0.677700 -0.723600 0.130500
+vn -0.677700 0.723600 -0.130500
+vn 0.714200 -0.586100 0.382500
+vn 0.673900 -0.419000 0.608600
+vn -0.673900 0.419000 0.608600
+vn 0.673900 -0.419000 -0.608600
+vn 0.337600 -0.180500 -0.923800
+vn 0.742600 -0.279500 0.608600
+vn -0.742700 0.279500 0.608600
+vn -0.742700 0.279500 -0.608600
+vn 0.742600 -0.279500 -0.608600
+vn -0.128800 -0.021300 -0.991400
+vn 0.128800 0.021300 -0.991400
+vn 0.337600 0.180500 0.923800
+vn 0.677700 0.723600 0.130500
+vn -0.677700 -0.723600 0.130500
+vn 0.419000 0.673800 -0.608600
+vn -0.180500 -0.337600 0.923800
+vn -0.180500 -0.337600 -0.923800
+vn 0.180500 0.337600 -0.923800
+vn -0.279500 -0.742600 0.608600
+vn -0.279500 -0.742600 -0.608600
+vn -0.180200 -0.772800 0.608500
+vn -0.032400 0.990900 0.130400
+vn -0.032400 0.990900 -0.130400
+vn -0.021300 0.128800 0.991400
+vn -0.419000 0.673800 -0.608600
+vn 0.723600 -0.677700 0.130500
+vn 0.723600 -0.677700 -0.130500
+vn -0.723600 0.677800 -0.130500
+vn 0.128800 -0.021300 -0.991400
+vn -0.128800 0.021300 -0.991400
+vn -0.742600 -0.279500 0.608600
+vn -0.742600 -0.279500 -0.608600
+vn -0.673800 -0.419000 0.608600
+vn -0.673800 -0.419000 -0.608600
+vn -0.419000 -0.673800 0.608600
+vn -0.419000 -0.673800 -0.608600
+vn -0.021300 -0.128800 -0.991400
+vn 0.021300 -0.128800 -0.991400
+vn -0.677700 0.723600 0.130500
+vn 0.677700 -0.723600 -0.130500
+vn 0.814900 -0.435600 0.382500
+vn -0.814900 0.435600 -0.382500
+vn 0.814900 -0.435600 -0.382500
+s off
+f 25//1 26//1 2//1
+f 26//2 27//2 3//2
+f 3//3 27//3 28//3
+f 28//4 29//4 5//4
+f 5//5 29//5 30//5
+f 30//6 31//6 7//6
+f 31//7 32//7 8//7
+f 32//8 33//8 9//8
+f 9//9 33//9 34//9
+f 34//10 35//10 11//10
+f 35//11 36//11 12//11
+f 36//12 37//12 13//12
+f 13//13 37//13 38//13
+f 14//14 38//14 39//14
+f 39//15 40//15 16//15
+f 40//16 41//16 17//16
+f 41//17 42//17 18//17
+f 18//18 42//18 43//18
+f 19//19 43//19 44//19
+f 44//20 45//20 21//20
+f 45//21 46//21 22//21
+f 46//22 47//22 23//22
+f 23//23 47//23 48//23
+f 24//24 48//24 25//24
+f 49//25 50//25 26//25
+f 26//26 50//26 51//26
+f 27//27 51//27 52//27
+f 28//28 52//28 53//28
+f 29//29 53//29 54//29
+f 54//30 55//30 31//30
+f 31//31 55//31 56//31
+f 32//32 56//32 57//32
+f 33//33 57//33 58//33
+f 34//34 58//34 59//34
+f 35//35 59//35 60//35
+f 36//36 60//36 61//36
+f 61//37 62//37 38//37
+f 62//38 63//38 39//38
+f 63//39 64//39 40//39
+f 64//40 65//40 41//40
+f 65//41 66//41 42//41
+f 66//42 67//42 43//42
+f 67//43 68//43 44//43
+f 68//44 69//44 45//44
+f 69//45 70//45 46//45
+f 70//46 71//46 47//46
+f 71//47 72//47 48//47
+f 48//48 72//48 49//48
+f 73//49 74//49 50//49
+f 50//50 74//50 75//50
+f 75//51 76//51 52//51
+f 76//52 77//52 53//52
+f 77//53 78//53 54//53
+f 54//54 78//54 79//54
+f 79//55 80//55 56//55
+f 80//56 81//56 57//56
+f 81//57 82//57 58//57
+f 82//58 83//58 59//58
+f 59//59 83//59 84//59
+f 60//60 84//60 85//60
+f 85//61 86//61 62//61
+f 86//62 87//62 63//62
+f 87//63 88//63 64//63
+f 64//64 88//64 89//64
+f 89//65 90//65 66//65
+f 90//66 91//66 67//66
+f 67//67 91//67 92//67
+f 68//68 92//68 93//68
+f 69//69 93//69 94//69
+f 70//70 94//70 95//70
+f 95//71 96//71 72//71
+f 96//72 73//72 49//72
+f 97//73 98//73 74//73
+f 98//74 99//74 75//74
+f 75//75 99//75 100//75
+f 76//76 100//76 101//76
+f 77//77 101//77 102//77
+f 78//78 102//78 103//78
+f 79//79 103//79 104//79
+f 80//80 104//80 105//80
+f 81//81 105//81 106//81
+f 106//82 107//82 83//82
+f 83//83 107//83 108//83
+f 108//84 109//84 85//84
+f 85//85 109//85 110//85
+f 110//86 111//86 87//86
+f 87//87 111//87 112//87
+f 112//88 113//88 89//88
+f 113//89 114//89 90//89
+f 114//90 115//90 91//90
+f 115//91 116//91 92//91
+f 116//92 117//92 93//92
+f 117//93 118//93 94//93
+f 118//94 119//94 95//94
+f 95//95 119//95 120//95
+f 120//96 97//96 73//96
+f 121//97 122//97 98//97
+f 98//98 122//98 123//98
+f 123//99 124//99 100//99
+f 124//100 125//100 101//100
+f 125//101 126//101 102//101
+f 126//102 127//102 103//102
+f 127//103 128//103 104//103
+f 128//104 129//104 105//104
+f 129//105 130//105 106//105
+f 130//106 131//106 107//106
+f 131//107 132//107 108//107
+f 132//108 133//108 109//108
+f 133//109 134//109 110//109
+f 110//110 134//110 135//110
+f 111//111 135//111 136//111
+f 112//112 136//112 137//112
+f 113//113 137//113 138//113
+f 114//114 138//114 139//114
+f 115//115 139//115 140//115
+f 116//116 140//116 141//116
+f 117//117 141//117 142//117
+f 118//118 142//118 143//118
+f 143//119 144//119 120//119
+f 120//120 144//120 121//120
+f 145//121 146//121 122//121
+f 122//122 146//122 147//122
+f 123//123 147//123 148//123
+f 124//124 148//124 149//124
+f 125//125 149//125 150//125
+f 150//126 151//126 127//126
+f 127//127 151//127 152//127
+f 152//128 153//128 129//128
+f 153//129 154//129 130//129
+f 130//130 154//130 155//130
+f 155//131 156//131 132//131
+f 132//132 156//132 157//132
+f 157//133 158//133 134//133
+f 158//134 159//134 135//134
+f 159//135 160//135 136//135
+f 160//136 161//136 137//136
+f 137//137 161//137 162//137
+f 162//138 163//138 139//138
+f 163//139 164//139 140//139
+f 164//140 165//140 141//140
+f 165//141 166//141 142//141
+f 166//142 167//142 143//142
+f 167//143 168//143 144//143
+f 168//144 145//144 121//144
+f 169//145 170//145 146//145
+f 170//146 171//146 147//146
+f 147//147 171//147 172//147
+f 172//148 173//148 149//148
+f 173//149 174//149 150//149
+f 174//150 175//150 151//150
+f 175//151 176//151 152//151
+f 176//152 177//152 153//152
+f 177//153 178//153 154//153
+f 178//154 179//154 155//154
+f 179//155 180//155 156//155
+f 180//156 181//156 157//156
+f 157//157 181//157 182//157
+f 158//158 182//158 183//158
+f 159//159 183//159 184//159
+f 160//160 184//160 185//160
+f 161//161 185//161 186//161
+f 162//162 186//162 187//162
+f 187//163 188//163 164//163
+f 164//164 188//164 189//164
+f 165//165 189//165 190//165
+f 190//166 191//166 167//166
+f 167//167 191//167 192//167
+f 168//168 192//168 169//168
+f 193//169 194//169 170//169
+f 170//170 194//170 195//170
+f 171//171 195//171 196//171
+f 172//172 196//172 197//172
+f 173//173 197//173 198//173
+f 174//174 198//174 199//174
+f 199//175 200//175 176//175
+f 176//176 200//176 201//176
+f 201//177 202//177 178//177
+f 178//178 202//178 203//178
+f 179//179 203//179 204//179
+f 204//180 205//180 181//180
+f 181//181 205//181 206//181
+f 206//182 207//182 183//182
+f 207//183 208//183 184//183
+f 208//184 209//184 185//184
+f 209//185 210//185 186//185
+f 210//186 211//186 187//186
+f 187//187 211//187 212//187
+f 212//188 213//188 189//188
+f 213//189 214//189 190//189
+f 214//190 215//190 191//190
+f 215//191 216//191 192//191
+f 216//192 193//192 169//192
+f 217//193 218//193 194//193
+f 218//194 219//194 195//194
+f 195//195 219//195 220//195
+f 220//196 221//196 197//196
+f 197//197 221//197 222//197
+f 198//198 222//198 223//198
+f 199//199 223//199 224//199
+f 224//200 225//200 201//200
+f 225//201 226//201 202//201
+f 226//202 227//202 203//202
+f 227//203 228//203 204//203
+f 204//204 228//204 229//204
+f 229//205 230//205 206//205
+f 206//206 230//206 231//206
+f 207//207 231//207 232//207
+f 208//208 232//208 233//208
+f 233//209 234//209 210//209
+f 234//210 235//210 211//210
+f 235//211 236//211 212//211
+f 236//212 237//212 213//212
+f 237//213 238//213 214//213
+f 238//214 239//214 215//214
+f 215//215 239//215 240//215
+f 216//216 240//216 217//216
+f 241//217 242//217 218//217
+f 242//218 243//218 219//218
+f 219//219 243//219 244//219
+f 244//220 245//220 221//220
+f 245//221 246//221 222//221
+f 246//222 247//222 223//222
+f 223//223 247//223 248//223
+f 224//224 248//224 249//224
+f 225//225 249//225 250//225
+f 226//226 250//226 251//226
+f 227//227 251//227 252//227
+f 252//228 253//228 229//228
+f 253//229 254//229 230//229
+f 230//230 254//230 255//230
+f 255//231 256//231 232//231
+f 256//232 257//232 233//232
+f 233//233 257//233 258//233
+f 258//234 259//234 235//234
+f 235//235 259//235 260//235
+f 236//236 260//236 261//236
+f 237//237 261//237 262//237
+f 262//238 263//238 239//238
+f 239//239 263//239 264//239
+f 264//240 241//240 217//240
+f 241//241 265//241 266//241
+f 266//242 267//242 243//242
+f 267//243 268//243 244//243
+f 268//244 269//244 245//244
+f 269//245 270//245 246//245
+f 246//246 270//246 271//246
+f 271//247 272//247 248//247
+f 272//248 273//248 249//248
+f 249//249 273//249 274//249
+f 274//250 275//250 251//250
+f 275//251 276//251 252//251
+f 276//252 277//252 253//252
+f 253//253 277//253 278//253
+f 278//254 279//254 255//254
+f 255//255 279//255 280//255
+f 280//256 281//256 257//256
+f 257//257 281//257 282//257
+f 258//258 282//258 283//258
+f 283//259 284//259 260//259
+f 260//260 284//260 285//260
+f 261//261 285//261 286//261
+f 286//262 287//262 263//262
+f 287//263 288//263 264//263
+f 288//264 265//264 241//264
+f 265//265 289//265 290//265
+f 290//266 291//266 267//266
+f 267//267 291//267 292//267
+f 292//268 293//268 269//268
+f 293//269 294//269 270//269
+f 294//270 295//270 271//270
+f 295//271 296//271 272//271
+f 296//272 297//272 273//272
+f 273//273 297//273 298//273
+f 298//274 299//274 275//274
+f 299//275 300//275 276//275
+f 300//276 301//276 277//276
+f 301//277 302//277 278//277
+f 278//278 302//278 303//278
+f 279//279 303//279 304//279
+f 304//280 305//280 281//280
+f 305//281 306//281 282//281
+f 282//282 306//282 307//282
+f 283//283 307//283 308//283
+f 308//284 309//284 285//284
+f 285//285 309//285 310//285
+f 310//286 311//286 287//286
+f 311//287 312//287 288//287
+f 312//288 289//288 265//288
+f 289//289 313//289 314//289
+f 314//290 315//290 291//290
+f 291//291 315//291 316//291
+f 292//292 316//292 317//292
+f 293//293 317//293 318//293
+f 294//294 318//294 319//294
+f 295//295 319//295 320//295
+f 320//296 321//296 297//296
+f 321//297 322//297 298//297
+f 322//298 323//298 299//298
+f 323//299 324//299 300//299
+f 324//300 325//300 301//300
+f 325//301 326//301 302//301
+f 302//302 326//302 327//302
+f 303//303 327//303 328//303
+f 328//304 329//304 305//304
+f 329//305 330//305 306//305
+f 330//306 331//306 307//306
+f 307//307 331//307 332//307
+f 332//308 333//308 309//308
+f 333//309 334//309 310//309
+f 334//310 335//310 311//310
+f 311//311 335//311 336//311
+f 336//312 313//312 289//312
+f 337//313 338//313 314//313
+f 314//314 338//314 339//314
+f 315//315 339//315 340//315
+f 340//316 341//316 317//316
+f 341//317 342//317 318//317
+f 318//318 342//318 343//318
+f 343//319 344//319 320//319
+f 344//320 345//320 321//320
+f 321//321 345//321 346//321
+f 346//322 347//322 323//322
+f 323//323 347//323 348//323
+f 348//324 349//324 325//324
+f 325//325 349//325 350//325
+f 350//326 351//326 327//326
+f 327//327 351//327 352//327
+f 352//328 353//328 329//328
+f 353//329 354//329 330//329
+f 330//330 354//330 355//330
+f 355//331 356//331 332//331
+f 332//332 356//332 357//332
+f 333//333 357//333 358//333
+f 358//334 359//334 335//334
+f 359//335 360//335 336//335
+f 336//336 360//336 337//336
+f 337//337 361//337 362//337
+f 362//338 363//338 339//338
+f 339//339 363//339 364//339
+f 364//340 365//340 341//340
+f 365//341 366//341 342//341
+f 342//342 366//342 367//342
+f 367//343 368//343 344//343
+f 368//344 369//344 345//344
+f 345//345 369//345 370//345
+f 346//346 370//346 371//346
+f 347//347 371//347 372//347
+f 372//348 373//348 349//348
+f 373//349 374//349 350//349
+f 374//350 375//350 351//350
+f 375//351 376//351 352//351
+f 376//352 377//352 353//352
+f 377//353 378//353 354//353
+f 378//354 379//354 355//354
+f 379//355 380//355 356//355
+f 380//356 381//356 357//356
+f 381//357 382//357 358//357
+f 382//358 383//358 359//358
+f 359//359 383//359 384//359
+f 360//360 384//360 361//360
+f 385//361 386//361 362//361
+f 386//362 387//362 363//362
+f 363//363 387//363 388//363
+f 388//364 389//364 365//364
+f 365//365 389//365 390//365
+f 390//366 391//366 367//366
+f 391//367 392//367 368//367
+f 392//368 393//368 369//368
+f 393//369 394//369 370//369
+f 394//370 395//370 371//370
+f 371//371 395//371 396//371
+f 396//372 397//372 373//372
+f 373//373 397//373 398//373
+f 398//374 399//374 375//374
+f 375//375 399//375 400//375
+f 400//376 401//376 377//376
+f 377//377 401//377 402//377
+f 378//378 402//378 403//378
+f 379//379 403//379 404//379
+f 404//380 405//380 381//380
+f 381//381 405//381 406//381
+f 382//382 406//382 407//382
+f 383//383 407//383 408//383
+f 384//384 408//384 385//384
+f 385//385 409//385 410//385
+f 410//386 411//386 387//386
+f 387//387 411//387 412//387
+f 388//388 412//388 413//388
+f 413//389 414//389 390//389
+f 390//390 414//390 415//390
+f 391//391 415//391 416//391
+f 416//392 417//392 393//392
+f 393//393 417//393 418//393
+f 418//394 419//394 395//394
+f 395//395 419//395 420//395
+f 420//396 421//396 397//396
+f 421//397 422//397 398//397
+f 422//398 423//398 399//398
+f 399//399 423//399 424//399
+f 424//400 425//400 401//400
+f 401//401 425//401 426//401
+f 426//402 427//402 403//402
+f 427//403 428//403 404//403
+f 428//404 429//404 405//404
+f 429//405 430//405 406//405
+f 430//406 431//406 407//406
+f 407//407 431//407 432//407
+f 432//408 409//408 385//408
+f 409//409 433//409 434//409
+f 434//410 435//410 411//410
+f 411//411 435//411 436//411
+f 436//412 437//412 413//412
+f 437//413 438//413 414//413
+f 438//414 439//414 415//414
+f 439//415 440//415 416//415
+f 440//416 441//416 417//416
+f 417//417 441//417 442//417
+f 442//418 443//418 419//418
+f 443//419 444//419 420//419
+f 444//420 445//420 421//420
+f 445//421 446//421 422//421
+f 422//422 446//422 447//422
+f 423//423 447//423 448//423
+f 448//424 449//424 425//424
+f 425//425 449//425 450//425
+f 426//426 450//426 451//426
+f 427//427 451//427 452//427
+f 428//428 452//428 453//428
+f 429//429 453//429 454//429
+f 454//430 455//430 431//430
+f 431//431 455//431 456//431
+f 456//432 433//432 409//432
+f 457//433 458//433 434//433
+f 458//434 459//434 435//434
+f 435//435 459//435 460//435
+f 460//436 461//436 437//436
+f 437//437 461//437 462//437
+f 462//438 463//438 439//438
+f 439//439 463//439 464//439
+f 440//440 464//440 465//440
+f 441//441 465//441 466//441
+f 442//442 466//442 467//442
+f 467//443 468//443 444//443
+f 444//444 468//444 469//444
+f 469//445 470//445 446//445
+f 470//446 471//446 447//446
+f 471//447 472//447 448//447
+f 472//448 473//448 449//448
+f 473//449 474//449 450//449
+f 474//450 475//450 451//450
+f 451//451 475//451 476//451
+f 476//452 477//452 453//452
+f 453//453 477//453 478//453
+f 478//454 479//454 455//454
+f 479//455 480//455 456//455
+f 480//456 457//456 433//456
+f 481//457 482//457 458//457
+f 482//458 483//458 459//458
+f 483//459 484//459 460//459
+f 484//460 485//460 461//460
+f 461//461 485//461 486//461
+f 486//462 487//462 463//462
+f 487//463 488//463 464//463
+f 464//464 488//464 489//464
+f 489//465 490//465 466//465
+f 490//466 491//466 467//466
+f 491//467 492//467 468//467
+f 468//468 492//468 493//468
+f 493//469 494//469 470//469
+f 494//470 495//470 471//470
+f 471//471 495//471 496//471
+f 472//472 496//472 497//472
+f 497//473 498//473 474//473
+f 498//474 499//474 475//474
+f 475//475 499//475 500//475
+f 500//476 501//476 477//476
+f 477//477 501//477 502//477
+f 502//478 503//478 479//478
+f 479//479 503//479 504//479
+f 504//480 481//480 457//480
+f 481//481 505//481 506//481
+f 482//482 506//482 507//482
+f 507//483 508//483 484//483
+f 508//484 509//484 485//484
+f 509//485 510//485 486//485
+f 510//486 511//486 487//486
+f 487//487 511//487 512//487
+f 512//488 513//488 489//488
+f 513//489 514//489 490//489
+f 514//490 515//490 491//490
+f 515//491 516//491 492//491
+f 492//492 516//492 517//492
+f 517//493 518//493 494//493
+f 494//494 518//494 519//494
+f 519//495 520//495 496//495
+f 496//496 520//496 521//496
+f 521//497 522//497 498//497
+f 522//498 523//498 499//498
+f 499//499 523//499 524//499
+f 500//500 524//500 525//500
+f 501//501 525//501 526//501
+f 502//502 526//502 527//502
+f 503//503 527//503 528//503
+f 528//504 505//504 481//504
+f 505//505 529//505 530//505
+f 530//506 531//506 507//506
+f 531//507 532//507 508//507
+f 508//508 532//508 533//508
+f 533//509 534//509 510//509
+f 534//510 535//510 511//510
+f 511//511 535//511 536//511
+f 536//512 537//512 513//512
+f 537//513 538//513 514//513
+f 514//514 538//514 539//514
+f 539//515 540//515 516//515
+f 516//516 540//516 541//516
+f 541//517 542//517 518//517
+f 542//518 543//518 519//518
+f 543//519 544//519 520//519
+f 520//520 544//520 545//520
+f 521//521 545//521 546//521
+f 546//522 547//522 523//522
+f 547//523 548//523 524//523
+f 548//524 549//524 525//524
+f 549//525 550//525 526//525
+f 550//526 551//526 527//526
+f 527//527 551//527 552//527
+f 552//528 529//528 505//528
+f 529//529 553//529 554//529
+f 530//530 554//530 555//530
+f 531//531 555//531 556//531
+f 556//532 557//532 533//532
+f 557//533 558//533 534//533
+f 534//534 558//534 559//534
+f 535//535 559//535 560//535
+f 560//536 561//536 537//536
+f 561//537 562//537 538//537
+f 538//538 562//538 563//538
+f 539//539 563//539 564//539
+f 564//540 565//540 541//540
+f 565//541 566//541 542//541
+f 566//542 567//542 543//542
+f 567//543 568//543 544//543
+f 544//544 568//544 569//544
+f 569//545 570//545 546//545
+f 570//546 571//546 547//546
+f 547//547 571//547 572//547
+f 572//548 573//548 549//548
+f 549//549 573//549 574//549
+f 574//550 575//550 551//550
+f 575//551 576//551 552//551
+f 576//552 553//552 529//552
+f 577//553 578//553 554//553
+f 554//554 578//554 579//554
+f 579//555 580//555 556//555
+f 556//556 580//556 581//556
+f 581//557 582//557 558//557
+f 558//558 582//558 583//558
+f 559//559 583//559 584//559
+f 560//560 584//560 585//560
+f 561//561 585//561 586//561
+f 586//562 587//562 563//562
+f 563//563 587//563 588//563
+f 588//564 589//564 565//564
+f 565//565 589//565 590//565
+f 590//566 591//566 567//566
+f 567//567 591//567 592//567
+f 592//568 593//568 569//568
+f 593//569 594//569 570//569
+f 594//570 595//570 571//570
+f 595//571 596//571 572//571
+f 596//572 597//572 573//572
+f 597//573 598//573 574//573
+f 574//574 598//574 599//574
+f 599//575 600//575 576//575
+f 600//576 577//576 553//576
+f 577//577 601//577 602//577
+f 578//578 602//578 603//578
+f 603//579 604//579 580//579
+f 604//580 605//580 581//580
+f 605//581 606//581 582//581
+f 582//582 606//582 607//582
+f 607//583 608//583 584//583
+f 608//584 609//584 585//584
+f 585//585 609//585 610//585
+f 610//586 611//586 587//586
+f 587//587 611//587 612//587
+f 612//588 613//588 589//588
+f 589//589 613//589 614//589
+f 614//590 615//590 591//590
+f 615//591 616//591 592//591
+f 616//592 617//592 593//592
+f 593//593 617//593 618//593
+f 594//594 618//594 619//594
+f 619//595 620//595 596//595
+f 596//596 620//596 621//596
+f 597//597 621//597 622//597
+f 598//598 622//598 623//598
+f 623//599 624//599 600//599
+f 624//600 601//600 577//600
+f 601//601 625//601 626//601
+f 626//602 627//602 603//602
+f 603//603 627//603 628//603
+f 604//604 628//604 629//604
+f 629//605 630//605 606//605
+f 606//606 630//606 631//606
+f 607//607 631//607 632//607
+f 632//608 633//608 609//608
+f 633//609 634//609 610//609
+f 634//610 635//610 611//610
+f 635//611 636//611 612//611
+f 636//612 637//612 613//612
+f 637//613 638//613 614//613
+f 614//614 638//614 639//614
+f 615//615 639//615 640//615
+f 640//616 641//616 617//616
+f 641//617 642//617 618//617
+f 642//618 643//618 619//618
+f 643//619 644//619 620//619
+f 620//620 644//620 645//620
+f 645//621 646//621 622//621
+f 646//622 647//622 623//622
+f 623//623 647//623 648//623
+f 648//624 625//624 601//624
+f 649//625 650//625 626//625
+f 650//626 651//626 627//626
+f 651//627 652//627 628//627
+f 628//628 652//628 653//628
+f 653//629 654//629 630//629
+f 654//630 655//630 631//630
+f 655//631 656//631 632//631
+f 656//632 657//632 633//632
+f 633//633 657//633 658//633
+f 658//634 659//634 635//634
+f 635//635 659//635 660//635
+f 636//636 660//636 661//636
+f 661//637 662//637 638//637
+f 662//638 663//638 639//638
+f 663//639 664//639 640//639
+f 664//640 665//640 641//640
+f 665//641 666//641 642//641
+f 666//642 667//642 643//642
+f 643//643 667//643 668//643
+f 644//644 668//644 669//644
+f 669//645 670//645 646//645
+f 646//646 670//646 671//646
+f 647//647 671//647 672//647
+f 648//648 672//648 649//648
+f 649//649 673//649 674//649
+f 650//650 674//650 675//650
+f 675//651 676//651 652//651
+f 652//652 676//652 677//652
+f 653//653 677//653 678//653
+f 654//654 678//654 679//654
+f 655//655 679//655 680//655
+f 680//656 681//656 657//656
+f 657//657 681//657 682//657
+f 682//658 683//658 659//658
+f 659//659 683//659 684//659
+f 684//660 685//660 661//660
+f 685//661 686//661 662//661
+f 686//662 687//662 663//662
+f 663//663 687//663 688//663
+f 688//664 689//664 665//664
+f 689//665 690//665 666//665
+f 690//666 691//666 667//666
+f 691//667 692//667 668//667
+f 692//668 693//668 669//668
+f 669//669 693//669 694//669
+f 694//670 695//670 671//670
+f 695//671 696//671 672//671
+f 696//672 673//672 649//672
+f 697//673 698//673 674//673
+f 674//674 698//674 699//674
+f 699//675 700//675 676//675
+f 700//676 701//676 677//676
+f 701//677 702//677 678//677
+f 702//678 703//678 679//678
+f 679//679 703//679 704//679
+f 704//680 705//680 681//680
+f 705//681 706//681 682//681
+f 706//682 707//682 683//682
+f 707//683 708//683 684//683
+f 684//684 708//684 709//684
+f 709//685 710//685 686//685
+f 686//686 710//686 711//686
+f 687//687 711//687 712//687
+f 688//688 712//688 713//688
+f 689//689 713//689 714//689
+f 714//690 715//690 691//690
+f 691//691 715//691 716//691
+f 692//692 716//692 717//692
+f 693//693 717//693 718//693
+f 694//694 718//694 719//694
+f 719//695 720//695 696//695
+f 696//696 720//696 697//696
+f 697//697 721//697 722//697
+f 698//698 722//698 723//698
+f 723//699 724//699 700//699
+f 700//700 724//700 725//700
+f 701//701 725//701 726//701
+f 726//702 727//702 703//702
+f 727//703 728//703 704//703
+f 728//704 729//704 705//704
+f 729//705 730//705 706//705
+f 706//706 730//706 731//706
+f 731//707 732//707 708//707
+f 708//708 732//708 733//708
+f 733//709 734//709 710//709
+f 734//710 735//710 711//710
+f 735//711 736//711 712//711
+f 712//712 736//712 737//712
+f 737//713 738//713 714//713
+f 714//714 738//714 739//714
+f 739//715 740//715 716//715
+f 716//716 740//716 741//716
+f 741//717 742//717 718//717
+f 718//718 742//718 743//718
+f 743//719 744//719 720//719
+f 744//720 721//720 697//720
+f 721//721 745//721 746//721
+f 722//722 746//722 747//722
+f 747//723 748//723 724//723
+f 748//724 749//724 725//724
+f 749//725 750//725 726//725
+f 726//726 750//726 751//726
+f 751//727 752//727 728//727
+f 728//728 752//728 753//728
+f 753//729 754//729 730//729
+f 730//730 754//730 755//730
+f 755//731 756//731 732//731
+f 756//732 757//732 733//732
+f 733//733 757//733 758//733
+f 734//734 758//734 759//734
+f 759//735 760//735 736//735
+f 760//736 761//736 737//736
+f 761//737 762//737 738//737
+f 738//738 762//738 763//738
+f 763//739 764//739 740//739
+f 740//740 764//740 765//740
+f 741//741 765//741 766//741
+f 742//742 766//742 767//742
+f 767//743 768//743 744//743
+f 768//744 745//744 721//744
+f 745//745 769//745 770//745
+f 746//746 770//746 771//746
+f 747//747 771//747 772//747
+f 772//748 773//748 749//748
+f 749//749 773//749 774//749
+f 774//750 775//750 751//750
+f 751//751 775//751 776//751
+f 752//752 776//752 777//752
+f 753//753 777//753 778//753
+f 754//754 778//754 779//754
+f 779//755 780//755 756//755
+f 780//756 781//756 757//756
+f 757//757 781//757 782//757
+f 758//758 782//758 783//758
+f 783//759 784//759 760//759
+f 784//760 785//760 761//760
+f 785//761 786//761 762//761
+f 786//762 787//762 763//762
+f 787//763 788//763 764//763
+f 788//764 789//764 765//764
+f 765//765 789//765 790//765
+f 790//766 791//766 767//766
+f 791//767 792//767 768//767
+f 792//768 769//768 745//768
+f 769//769 793//769 794//769
+f 794//770 795//770 771//770
+f 795//771 796//771 772//771
+f 796//772 797//772 773//772
+f 797//773 798//773 774//773
+f 798//774 799//774 775//774
+f 799//775 800//775 776//775
+f 800//776 801//776 777//776
+f 801//777 802//777 778//777
+f 802//778 803//778 779//778
+f 803//779 804//779 780//779
+f 804//780 805//780 781//780
+f 805//781 806//781 782//781
+f 782//782 806//782 807//782
+f 783//783 807//783 808//783
+f 808//784 809//784 785//784
+f 785//785 809//785 810//785
+f 786//786 810//786 811//786
+f 787//787 811//787 812//787
+f 812//788 813//788 789//788
+f 789//789 813//789 814//789
+f 814//790 815//790 791//790
+f 791//791 815//791 816//791
+f 816//792 793//792 769//792
+f 793//793 817//793 818//793
+f 818//794 819//794 795//794
+f 795//795 819//795 820//795
+f 796//796 820//796 821//796
+f 797//797 821//797 822//797
+f 798//798 822//798 823//798
+f 799//799 823//799 824//799
+f 800//800 824//800 825//800
+f 825//801 826//801 802//801
+f 802//802 826//802 827//802
+f 827//803 828//803 804//803
+f 804//804 828//804 829//804
+f 829//805 830//805 806//805
+f 830//806 831//806 807//806
+f 831//807 832//807 808//807
+f 832//808 833//808 809//808
+f 833//809 834//809 810//809
+f 834//810 835//810 811//810
+f 835//811 836//811 812//811
+f 836//812 837//812 813//812
+f 837//813 838//813 814//813
+f 838//814 839//814 815//814
+f 815//815 839//815 840//815
+f 840//816 817//816 793//816
+f 841//817 842//817 818//817
+f 842//818 843//818 819//818
+f 819//819 843//819 844//819
+f 844//820 845//820 821//820
+f 821//821 845//821 846//821
+f 846//822 847//822 823//822
+f 847//823 848//823 824//823
+f 824//824 848//824 849//824
+f 849//825 850//825 826//825
+f 850//826 851//826 827//826
+f 851//827 852//827 828//827
+f 828//828 852//828 853//828
+f 853//829 854//829 830//829
+f 830//830 854//830 855//830
+f 831//831 855//831 856//831
+f 832//832 856//832 857//832
+f 857//833 858//833 834//833
+f 834//834 858//834 859//834
+f 859//835 860//835 836//835
+f 860//836 861//836 837//836
+f 861//837 862//837 838//837
+f 862//838 863//838 839//838
+f 863//839 864//839 840//839
+f 840//840 864//840 841//840
+f 865//841 866//841 842//841
+f 842//842 866//842 867//842
+f 867//843 868//843 844//843
+f 868//844 869//844 845//844
+f 845//845 869//845 870//845
+f 846//846 870//846 871//846
+f 871//847 872//847 848//847
+f 848//848 872//848 873//848
+f 849//849 873//849 874//849
+f 874//850 875//850 851//850
+f 875//851 876//851 852//851
+f 852//852 876//852 877//852
+f 877//853 878//853 854//853
+f 854//854 878//854 879//854
+f 855//855 879//855 880//855
+f 856//856 880//856 881//856
+f 881//857 882//857 858//857
+f 858//858 882//858 883//858
+f 859//859 883//859 884//859
+f 884//860 885//860 861//860
+f 885//861 886//861 862//861
+f 862//862 886//862 887//862
+f 887//863 888//863 864//863
+f 864//864 888//864 865//864
+f 889//865 890//865 866//865
+f 866//866 890//866 891//866
+f 891//867 892//867 868//867
+f 868//868 892//868 893//868
+f 893//869 894//869 870//869
+f 894//870 895//870 871//870
+f 895//871 896//871 872//871
+f 896//872 897//872 873//872
+f 873//873 897//873 898//873
+f 874//874 898//874 899//874
+f 875//875 899//875 900//875
+f 876//876 900//876 901//876
+f 901//877 902//877 878//877
+f 878//878 902//878 903//878
+f 903//879 904//879 880//879
+f 880//880 904//880 905//880
+f 905//881 906//881 882//881
+f 882//882 906//882 907//882
+f 883//883 907//883 908//883
+f 908//884 909//884 885//884
+f 909//885 910//885 886//885
+f 886//886 910//886 911//886
+f 911//887 912//887 888//887
+f 888//888 912//888 889//888
+f 913//889 914//889 890//889
+f 914//890 915//890 891//890
+f 915//891 916//891 892//891
+f 892//892 916//892 917//892
+f 917//893 918//893 894//893
+f 918//894 919//894 895//894
+f 919//895 920//895 896//895
+f 896//896 920//896 921//896
+f 921//897 922//897 898//897
+f 898//898 922//898 923//898
+f 923//899 924//899 900//899
+f 924//900 925//900 901//900
+f 925//901 926//901 902//901
+f 902//902 926//902 927//902
+f 927//903 928//903 904//903
+f 904//904 928//904 929//904
+f 929//905 930//905 906//905
+f 930//906 931//906 907//906
+f 907//907 931//907 932//907
+f 908//908 932//908 933//908
+f 933//909 934//909 910//909
+f 910//910 934//910 935//910
+f 935//911 936//911 912//911
+f 912//912 936//912 913//912
+f 913//913 937//913 938//913
+f 914//914 938//914 939//914
+f 939//915 940//915 916//915
+f 940//916 941//916 917//916
+f 917//917 941//917 942//917
+f 942//918 943//918 919//918
+f 943//919 944//919 920//919
+f 944//920 945//920 921//920
+f 945//921 946//921 922//921
+f 946//922 947//922 923//922
+f 947//923 948//923 924//923
+f 924//924 948//924 949//924
+f 925//925 949//925 950//925
+f 950//926 951//926 927//926
+f 927//927 951//927 952//927
+f 952//928 953//928 929//928
+f 929//929 953//929 954//929
+f 954//930 955//930 931//930
+f 931//931 955//931 956//931
+f 956//932 957//932 933//932
+f 957//933 958//933 934//933
+f 934//934 958//934 959//934
+f 959//935 960//935 936//935
+f 960//936 937//936 913//936
+f 937//937 961//937 962//937
+f 938//938 962//938 963//938
+f 939//939 963//939 964//939
+f 940//940 964//940 965//940
+f 941//941 965//941 966//941
+f 942//942 966//942 967//942
+f 943//943 967//943 968//943
+f 944//944 968//944 969//944
+f 945//945 969//945 970//945
+f 946//946 970//946 971//946
+f 947//947 971//947 972//947
+f 972//948 973//948 949//948
+f 949//949 973//949 974//949
+f 974//950 975//950 951//950
+f 975//951 976//951 952//951
+f 976//952 977//952 953//952
+f 977//953 978//953 954//953
+f 978//954 979//954 955//954
+f 979//955 980//955 956//955
+f 980//956 981//956 957//956
+f 981//957 982//957 958//957
+f 958//958 982//958 983//958
+f 983//959 984//959 960//959
+f 984//960 961//960 937//960
+f 961//961 985//961 986//961
+f 962//962 986//962 987//962
+f 963//963 987//963 988//963
+f 988//964 989//964 965//964
+f 989//965 990//965 966//965
+f 966//966 990//966 991//966
+f 991//967 992//967 968//967
+f 992//968 993//968 969//968
+f 993//969 994//969 970//969
+f 994//970 995//970 971//970
+f 971//971 995//971 996//971
+f 996//972 997//972 973//972
+f 973//973 997//973 998//973
+f 998//974 999//974 975//974
+f 999//975 1000//975 976//975
+f 1000//976 1001//976 977//976
+f 977//977 1001//977 1002//977
+f 1002//978 1003//978 979//978
+f 1003//979 1004//979 980//979
+f 980//980 1004//980 1005//980
+f 1005//981 1006//981 982//981
+f 1006//982 1007//982 983//982
+f 1007//983 1008//983 984//983
+f 1008//984 985//984 961//984
+f 1009//985 1010//985 986//985
+f 1010//986 1011//986 987//986
+f 1011//987 1012//987 988//987
+f 1012//988 1013//988 989//988
+f 1013//989 1014//989 990//989
+f 1014//990 1015//990 991//990
+f 1015//991 1016//991 992//991
+f 1016//992 1017//992 993//992
+f 1017//993 1018//993 994//993
+f 1018//994 1019//994 995//994
+f 1019//995 1020//995 996//995
+f 1020//996 1021//996 997//996
+f 1021//997 1022//997 998//997
+f 998//998 1022//998 1023//998
+f 1023//999 1024//999 1000//999
+f 1024//1000 1025//1000 1001//1000
+f 1001//1001 1025//1001 1026//1001
+f 1002//1002 1026//1002 1027//1002
+f 1003//1003 1027//1003 1028//1003
+f 1004//1004 1028//1004 1029//1004
+f 1029//1005 1030//1005 1006//1005
+f 1006//1006 1030//1006 1031//1006
+f 1007//1007 1031//1007 1032//1007
+f 1032//1008 1009//1008 985//1008
+f 1009//1009 1033//1009 1034//1009
+f 1010//1010 1034//1010 1035//1010
+f 1011//1011 1035//1011 1036//1011
+f 1036//1012 1037//1012 1013//1012
+f 1013//1013 1037//1013 1038//1013
+f 1014//1014 1038//1014 1039//1014
+f 1015//1015 1039//1015 1040//1015
+f 1016//1016 1040//1016 1041//1016
+f 1017//1017 1041//1017 1042//1017
+f 1018//1018 1042//1018 1043//1018
+f 1043//1019 1044//1019 1020//1019
+f 1020//1020 1044//1020 1045//1020
+f 1045//1021 1046//1021 1022//1021
+f 1046//1022 1047//1022 1023//1022
+f 1047//1023 1048//1023 1024//1023
+f 1048//1024 1049//1024 1025//1024
+f 1049//1025 1050//1025 1026//1025
+f 1050//1026 1051//1026 1027//1026
+f 1051//1027 1052//1027 1028//1027
+f 1052//1028 1053//1028 1029//1028
+f 1029//1029 1053//1029 1054//1029
+f 1054//1030 1055//1030 1031//1030
+f 1055//1031 1056//1031 1032//1031
+f 1056//1032 1033//1032 1009//1032
+f 1033//1033 1057//1033 1058//1033
+f 1058//1034 1059//1034 1035//1034
+f 1059//1035 1060//1035 1036//1035
+f 1036//1036 1060//1036 1061//1036
+f 1037//1037 1061//1037 1062//1037
+f 1062//1038 1063//1038 1039//1038
+f 1063//1039 1064//1039 1040//1039
+f 1040//1040 1064//1040 1065//1040
+f 1041//1041 1065//1041 1066//1041
+f 1042//1042 1066//1042 1067//1042
+f 1067//1043 1068//1043 1044//1043
+f 1068//1044 1069//1044 1045//1044
+f 1069//1045 1070//1045 1046//1045
+f 1046//1046 1070//1046 1071//1046
+f 1071//1047 1072//1047 1048//1047
+f 1072//1048 1073//1048 1049//1048
+f 1073//1049 1074//1049 1050//1049
+f 1050//1050 1074//1050 1075//1050
+f 1051//1051 1075//1051 1076//1051
+f 1076//1052 1077//1052 1053//1052
+f 1077//1053 1078//1053 1054//1053
+f 1078//1054 1079//1054 1055//1054
+f 1055//1055 1079//1055 1080//1055
+f 1080//1056 1057//1056 1033//1056
+f 1081//1057 1082//1057 1058//1057
+f 1058//1058 1082//1058 1083//1058
+f 1083//1059 1084//1059 1060//1059
+f 1084//1060 1085//1060 1061//1060
+f 1085//1061 1086//1061 1062//1061
+f 1086//1062 1087//1062 1063//1062
+f 1087//1063 1088//1063 1064//1063
+f 1088//1064 1089//1064 1065//1064
+f 1089//1065 1090//1065 1066//1065
+f 1066//1066 1090//1066 1091//1066
+f 1091//1067 1092//1067 1068//1067
+f 1092//1068 1093//1068 1069//1068
+f 1093//1069 1094//1069 1070//1069
+f 1070//1070 1094//1070 1095//1070
+f 1095//1071 1096//1071 1072//1071
+f 1072//1072 1096//1072 1097//1072
+f 1073//1073 1097//1073 1098//1073
+f 1074//1074 1098//1074 1099//1074
+f 1075//1075 1099//1075 1100//1075
+f 1076//1076 1100//1076 1101//1076
+f 1077//1077 1101//1077 1102//1077
+f 1078//1078 1102//1078 1103//1078
+f 1103//1079 1104//1079 1080//1079
+f 1080//1080 1104//1080 1081//1080
+f 1105//1081 1106//1081 1082//1081
+f 1106//1082 1107//1082 1083//1082
+f 1083//1083 1107//1083 1108//1083
+f 1084//1084 1108//1084 1109//1084
+f 1085//1085 1109//1085 1110//1085
+f 1086//1086 1110//1086 1111//1086
+f 1111//1087 1112//1087 1088//1087
+f 1088//1088 1112//1088 1113//1088
+f 1089//1089 1113//1089 1114//1089
+f 1090//1090 1114//1090 1115//1090
+f 1115//1091 1116//1091 1092//1091
+f 1116//1092 1117//1092 1093//1092
+f 1117//1093 1118//1093 1094//1093
+f 1118//1094 1119//1094 1095//1094
+f 1119//1095 1120//1095 1096//1095
+f 1120//1096 1121//1096 1097//1096
+f 1121//1097 1122//1097 1098//1097
+f 1122//1098 1123//1098 1099//1098
+f 1123//1099 1124//1099 1100//1099
+f 1124//1100 1125//1100 1101//1100
+f 1125//1101 1126//1101 1102//1101
+f 1126//1102 1127//1102 1103//1102
+f 1127//1103 1128//1103 1104//1103
+f 1104//1104 1128//1104 1105//1104
+f 1105//1105 1129//1105 1130//1105
+f 1130//1106 1131//1106 1107//1106
+f 1131//1107 1132//1107 1108//1107
+f 1132//1108 1133//1108 1109//1108
+f 1133//1109 1134//1109 1110//1109
+f 1134//1110 1135//1110 1111//1110
+f 1135//1111 1136//1111 1112//1111
+f 1136//1112 1137//1112 1113//1112
+f 1137//1113 1138//1113 1114//1113
+f 1138//1114 1139//1114 1115//1114
+f 1139//1115 1140//1115 1116//1115
+f 1140//1116 1141//1116 1117//1116
+f 1141//1117 1142//1117 1118//1117
+f 1118//1118 1142//1118 1143//1118
+f 1119//1119 1143//1119 1144//1119
+f 1120//1120 1144//1120 1145//1120
+f 1121//1121 1145//1121 1146//1121
+f 1122//1122 1146//1122 1147//1122
+f 1123//1123 1147//1123 1148//1123
+f 1148//1124 1149//1124 1125//1124
+f 1125//1125 1149//1125 1150//1125
+f 1126//1126 1150//1126 1151//1126
+f 1151//1127 1152//1127 1128//1127
+f 1152//1128 1129//1128 1105//1128
+f 1153//1129 1154//1129 1130//1129
+f 1130//1130 1154//1130 1155//1130
+f 1155//1131 1156//1131 1132//1131
+f 1156//1132 1157//1132 1133//1132
+f 1157//1133 1158//1133 1134//1133
+f 1158//1134 1159//1134 1135//1134
+f 1135//1135 1159//1135 1160//1135
+f 1160//1136 1161//1136 1137//1136
+f 1161//1137 1162//1137 1138//1137
+f 1162//1138 1163//1138 1139//1138
+f 1139//1139 1163//1139 1164//1139
+f 1164//1140 1165//1140 1141//1140
+f 1165//1141 1166//1141 1142//1141
+f 1166//1142 1167//1142 1143//1142
+f 1143//1143 1167//1143 1168//1143
+f 1168//1144 1169//1144 1145//1144
+f 1145//1145 1169//1145 1170//1145
+f 1170//1146 1171//1146 1147//1146
+f 1147//1147 1171//1147 1172//1147
+f 1148//1148 1172//1148 1173//1148
+f 1149//1149 1173//1149 1174//1149
+f 1150//1150 1174//1150 1175//1150
+f 1175//1151 1176//1151 1152//1151
+f 1176//1152 1153//1152 1129//1152
+f 1153//12 1177//12 1178//12
+f 1154//11 1178//11 1179//11
+f 1155//10 1179//10 1180//10
+f 1180//9 1181//9 1157//9
+f 1181//8 1182//8 1158//8
+f 1182//7 1183//7 1159//7
+f 1183//6 1184//6 1160//6
+f 1160//5 1184//5 1185//5
+f 1161//4 1185//4 1186//4
+f 1186//3 1187//3 1163//3
+f 1187//2 1188//2 1164//2
+f 1188//1 1189//1 1165//1
+f 1165//24 1189//24 1190//24
+f 1166//23 1190//23 1191//23
+f 1191//22 1192//22 1168//22
+f 1192//21 1193//21 1169//21
+f 1193//20 1194//20 1170//20
+f 1170//19 1194//19 1195//19
+f 1171//18 1195//18 1196//18
+f 1172//17 1196//17 1197//17
+f 1197//16 1198//16 1174//16
+f 1198//15 1199//15 1175//15
+f 1199//14 1200//14 1176//14
+f 1200//13 1177//13 1153//13
+f 1201//36 1202//36 1178//36
+f 1202//35 1203//35 1179//35
+f 1179//34 1203//34 1204//34
+f 1180//33 1204//33 1205//33
+f 1181//32 1205//32 1206//32
+f 1182//31 1206//31 1207//31
+f 1207//30 1208//30 1184//30
+f 1184//29 1208//29 1209//29
+f 1185//28 1209//28 1210//28
+f 1186//27 1210//27 1211//27
+f 1187//26 1211//26 1212//26
+f 1188//25 1212//25 1213//25
+f 1213//48 1214//48 1190//48
+f 1214//47 1215//47 1191//47
+f 1215//46 1216//46 1192//46
+f 1216//45 1217//45 1193//45
+f 1217//44 1218//44 1194//44
+f 1218//43 1219//43 1195//43
+f 1219//42 1220//42 1196//42
+f 1220//41 1221//41 1197//41
+f 1221//40 1222//40 1198//40
+f 1222//39 1223//39 1199//39
+f 1223//38 1224//38 1200//38
+f 1224//37 1201//37 1177//37
+f 1225//60 1226//60 1202//60
+f 1226//59 1227//59 1203//59
+f 1227//58 1228//58 1204//58
+f 1228//57 1229//57 1205//57
+f 1229//56 1230//56 1206//56
+f 1230//1153 1231//1153 1207//1153
+f 1231//1154 1232//1154 1208//1154
+f 1232//53 1233//53 1209//53
+f 1233//52 1234//52 1210//52
+f 1234//51 1235//51 1211//51
+f 1235//50 1236//50 1212//50
+f 1236//49 1237//49 1213//49
+f 1237//72 1238//72 1214//72
+f 1238//71 1239//71 1215//71
+f 1239//70 1240//70 1216//70
+f 1216//69 1240//69 1241//69
+f 1217//68 1241//68 1242//68
+f 1242//67 1243//67 1219//67
+f 1219//66 1243//66 1244//66
+f 1220//65 1244//65 1245//65
+f 1221//64 1245//64 1246//64
+f 1222//63 1246//63 1247//63
+f 1247//62 1248//62 1224//62
+f 1248//61 1225//61 1201//61
+f 1225//84 1249//84 1250//84
+f 1250//83 1251//83 1227//83
+f 1227//82 1251//82 1252//82
+f 1228//81 1252//81 1253//81
+f 1229//80 1253//80 1254//80
+f 1230//79 1254//79 1255//79
+f 1231//78 1255//78 1256//78
+f 1232//77 1256//77 1257//77
+f 1233//76 1257//76 1258//76
+f 1258//75 1259//75 1235//75
+f 1235//74 1259//74 1260//74
+f 1260//73 1261//73 1237//73
+f 1261//96 1262//96 1238//96
+f 1262//95 1263//95 1239//95
+f 1239//94 1263//94 1264//94
+f 1264//93 1265//93 1241//93
+f 1265//92 1266//92 1242//92
+f 1266//91 1267//91 1243//91
+f 1267//90 1268//90 1244//90
+f 1268//89 1269//89 1245//89
+f 1269//88 1270//88 1246//88
+f 1270//87 1271//87 1247//87
+f 1247//86 1271//86 1272//86
+f 1272//85 1249//85 1225//85
+f 1273//108 1274//108 1250//108
+f 1250//107 1274//107 1275//107
+f 1251//106 1275//106 1276//106
+f 1276//105 1277//105 1253//105
+f 1253//104 1277//104 1278//104
+f 1254//103 1278//103 1279//103
+f 1255//102 1279//102 1280//102
+f 1280//101 1281//101 1257//101
+f 1281//100 1282//100 1258//100
+f 1282//99 1283//99 1259//99
+f 1259//98 1283//98 1284//98
+f 1284//97 1285//97 1261//97
+f 1285//120 1286//120 1262//120
+f 1286//119 1287//119 1263//119
+f 1263//118 1287//118 1288//118
+f 1264//117 1288//117 1289//117
+f 1265//116 1289//116 1290//116
+f 1290//115 1291//115 1267//115
+f 1291//114 1292//114 1268//114
+f 1292//113 1293//113 1269//113
+f 1269//112 1293//112 1294//112
+f 1294//111 1295//111 1271//111
+f 1295//110 1296//110 1272//110
+f 1272//109 1296//109 1273//109
+f 1297//132 1298//132 1274//132
+f 1274//131 1298//131 1299//131
+f 1299//130 1300//130 1276//130
+f 1300//129 1301//129 1277//129
+f 1301//128 1302//128 1278//128
+f 1302//127 1303//127 1279//127
+f 1303//126 1304//126 1280//126
+f 1304//125 1305//125 1281//125
+f 1305//124 1306//124 1282//124
+f 1306//123 1307//123 1283//123
+f 1307//122 1308//122 1284//122
+f 1308//121 1309//121 1285//121
+f 1285//144 1309//144 1310//144
+f 1310//143 1311//143 1287//143
+f 1287//142 1311//142 1312//142
+f 1288//141 1312//141 1313//141
+f 1289//140 1313//140 1314//140
+f 1290//139 1314//139 1315//139
+f 1291//138 1315//138 1316//138
+f 1292//137 1316//137 1317//137
+f 1317//136 1318//136 1294//136
+f 1294//135 1318//135 1319//135
+f 1319//134 1320//134 1296//134
+f 1296//133 1320//133 1297//133
+f 1297//156 1321//156 1322//156
+f 1298//155 1322//155 1323//155
+f 1323//154 1324//154 1300//154
+f 1300//153 1324//153 1325//153
+f 1325//152 1326//152 1302//152
+f 1302//151 1326//151 1327//151
+f 1303//150 1327//150 1328//150
+f 1304//149 1328//149 1329//149
+f 1305//148 1329//148 1330//148
+f 1306//147 1330//147 1331//147
+f 1307//146 1331//146 1332//146
+f 1308//145 1332//145 1333//145
+f 1333//168 1334//168 1310//168
+f 1334//167 1335//167 1311//167
+f 1335//166 1336//166 1312//166
+f 1336//165 1337//165 1313//165
+f 1337//164 1338//164 1314//164
+f 1314//163 1338//163 1339//163
+f 1339//162 1340//162 1316//162
+f 1316//161 1340//161 1341//161
+f 1341//160 1342//160 1318//160
+f 1342//159 1343//159 1319//159
+f 1343//158 1344//158 1320//158
+f 1344//157 1321//157 1297//157
+f 1345//180 1346//180 1322//180
+f 1346//179 1347//179 1323//179
+f 1347//178 1348//178 1324//178
+f 1348//177 1349//177 1325//177
+f 1325//176 1349//176 1350//176
+f 1326//175 1350//175 1351//175
+f 1327//174 1351//174 1352//174
+f 1328//173 1352//173 1353//173
+f 1353//172 1354//172 1330//172
+f 1330//171 1354//171 1355//171
+f 1355//1155 1356//1155 1332//1155
+f 1356//169 1357//169 1333//169
+f 1357//192 1358//192 1334//192
+f 1358//191 1359//191 1335//191
+f 1359//190 1360//190 1336//190
+f 1360//189 1361//189 1337//189
+f 1361//188 1362//188 1338//188
+f 1362//187 1363//187 1339//187
+f 1363//186 1364//186 1340//186
+f 1364//185 1365//185 1341//185
+f 1365//184 1366//184 1342//184
+f 1342//183 1366//183 1367//183
+f 1343//182 1367//182 1368//182
+f 1368//181 1345//181 1321//181
+f 1369//204 1370//204 1346//204
+f 1370//203 1371//203 1347//203
+f 1371//202 1372//202 1348//202
+f 1372//201 1373//201 1349//201
+f 1373//200 1374//200 1350//200
+f 1350//199 1374//199 1375//199
+f 1375//198 1376//198 1352//198
+f 1376//197 1377//197 1353//197
+f 1377//196 1378//196 1354//196
+f 1378//1156 1379//1156 1355//1156
+f 1379//194 1380//194 1356//194
+f 1356//193 1380//193 1381//193
+f 1381//216 1382//216 1358//216
+f 1358//215 1382//215 1383//215
+f 1359//1157 1383//1157 1384//1157
+f 1360//213 1384//213 1385//213
+f 1361//212 1385//212 1386//212
+f 1362//211 1386//211 1387//211
+f 1387//210 1388//210 1364//210
+f 1364//209 1388//209 1389//209
+f 1365//208 1389//208 1390//208
+f 1366//207 1390//207 1391//207
+f 1367//206 1391//206 1392//206
+f 1392//205 1369//205 1345//205
+f 1393//228 1394//228 1370//228
+f 1394//227 1395//227 1371//227
+f 1371//226 1395//226 1396//226
+f 1396//225 1397//225 1373//225
+f 1397//224 1398//224 1374//224
+f 1374//223 1398//223 1399//223
+f 1399//222 1400//222 1376//222
+f 1376//221 1400//221 1401//221
+f 1401//220 1402//220 1378//220
+f 1378//219 1402//219 1403//219
+f 1403//218 1404//218 1380//218
+f 1404//217 1405//217 1381//217
+f 1405//240 1406//240 1382//240
+f 1406//239 1407//239 1383//239
+f 1407//238 1408//238 1384//238
+f 1384//237 1408//237 1409//237
+f 1409//236 1410//236 1386//236
+f 1410//235 1411//235 1387//235
+f 1411//234 1412//234 1388//234
+f 1388//233 1412//233 1413//233
+f 1413//232 1414//232 1390//232
+f 1414//231 1415//231 1391//231
+f 1391//230 1415//230 1416//230
+f 1392//229 1416//229 1393//229
+f 1417//252 1418//252 1394//252
+f 1418//251 1419//251 1395//251
+f 1395//250 1419//250 1420//250
+f 1420//249 1421//249 1397//249
+f 1397//248 1421//248 1422//248
+f 1398//247 1422//247 1423//247
+f 1423//246 1424//246 1400//246
+f 1400//245 1424//245 1425//245
+f 1401//244 1425//244 1426//244
+f 1426//243 1427//243 1403//243
+f 1403//242 1427//242 1428//242
+f 1404//241 1428//241 1429//241
+f 1429//264 1430//264 1406//264
+f 1430//263 1431//263 1407//263
+f 1407//262 1431//262 1432//262
+f 1432//261 1433//261 1409//261
+f 1433//260 1434//260 1410//260
+f 1410//259 1434//259 1435//259
+f 1435//258 1436//258 1412//258
+f 1436//257 1437//257 1413//257
+f 1413//256 1437//256 1438//256
+f 1438//255 1439//255 1415//255
+f 1439//254 1440//254 1416//254
+f 1440//253 1417//253 1393//253
+f 1417//1158 1441//1158 1442//1158
+f 1442//275 1443//275 1419//275
+f 1419//274 1443//274 1444//274
+f 1444//273 1445//273 1421//273
+f 1445//272 1446//272 1422//272
+f 1422//271 1446//271 1447//271
+f 1423//270 1447//270 1448//270
+f 1448//269 1449//269 1425//269
+f 1425//268 1449//268 1450//268
+f 1450//267 1451//267 1427//267
+f 1427//266 1451//266 1452//266
+f 1452//1159 1453//1159 1429//1159
+f 1429//1160 1453//1160 1454//1160
+f 1430//287 1454//287 1455//287
+f 1431//286 1455//286 1456//286
+f 1432//285 1456//285 1457//285
+f 1457//284 1458//284 1434//284
+f 1458//283 1459//283 1435//283
+f 1459//282 1460//282 1436//282
+f 1460//281 1461//281 1437//281
+f 1437//280 1461//280 1462//280
+f 1462//279 1463//279 1439//279
+f 1439//278 1463//278 1464//278
+f 1464//277 1441//277 1417//277
+f 1441//300 1465//300 1466//300
+f 1466//299 1467//299 1443//299
+f 1467//298 1468//298 1444//298
+f 1468//297 1469//297 1445//297
+f 1469//296 1470//296 1446//296
+f 1470//295 1471//295 1447//295
+f 1471//294 1472//294 1448//294
+f 1472//293 1473//293 1449//293
+f 1473//292 1474//292 1450//292
+f 1474//291 1475//291 1451//291
+f 1451//290 1475//290 1476//290
+f 1452//289 1476//289 1477//289
+f 1477//312 1478//312 1454//312
+f 1478//311 1479//311 1455//311
+f 1479//310 1480//310 1456//310
+f 1456//309 1480//309 1481//309
+f 1481//308 1482//308 1458//308
+f 1482//307 1483//307 1459//307
+f 1483//306 1484//306 1460//306
+f 1460//305 1484//305 1485//305
+f 1461//304 1485//304 1486//304
+f 1462//303 1486//303 1487//303
+f 1463//302 1487//302 1488//302
+f 1488//301 1465//301 1441//301
+f 1465//1161 1489//1161 1490//1161
+f 1490//1162 1491//1162 1467//1162
+f 1467//322 1491//322 1492//322
+f 1468//321 1492//321 1493//321
+f 1469//320 1493//320 1494//320
+f 1470//319 1494//319 1495//319
+f 1471//318 1495//318 1496//318
+f 1472//317 1496//317 1497//317
+f 1473//316 1497//316 1498//316
+f 1474//315 1498//315 1499//315
+f 1475//1163 1499//1163 1500//1163
+f 1500//313 1501//313 1477//313
+f 1501//336 1502//336 1478//336
+f 1502//1164 1503//1164 1479//1164
+f 1503//334 1504//334 1480//334
+f 1504//333 1505//333 1481//333
+f 1505//332 1506//332 1482//332
+f 1506//331 1507//331 1483//331
+f 1507//330 1508//330 1484//330
+f 1508//329 1509//329 1485//329
+f 1509//328 1510//328 1486//328
+f 1510//327 1511//327 1487//327
+f 1511//1165 1512//1165 1488//1165
+f 1512//1166 1489//1166 1465//1166
+f 1513//348 1514//348 1490//348
+f 1490//347 1514//347 1515//347
+f 1515//346 1516//346 1492//346
+f 1492//345 1516//345 1517//345
+f 1517//344 1518//344 1494//344
+f 1518//343 1519//343 1495//343
+f 1519//342 1520//342 1496//342
+f 1520//341 1521//341 1497//341
+f 1521//340 1522//340 1498//340
+f 1522//339 1523//339 1499//339
+f 1523//338 1524//338 1500//338
+f 1524//337 1525//337 1501//337
+f 1525//360 1526//360 1502//360
+f 1502//359 1526//359 1527//359
+f 1503//358 1527//358 1528//358
+f 1504//357 1528//357 1529//357
+f 1505//356 1529//356 1530//356
+f 1530//355 1531//355 1507//355
+f 1507//354 1531//354 1532//354
+f 1508//353 1532//353 1533//353
+f 1533//352 1534//352 1510//352
+f 1510//351 1534//351 1535//351
+f 1535//350 1536//350 1512//350
+f 1512//349 1536//349 1513//349
+f 1537//372 1538//372 1514//372
+f 1514//371 1538//371 1539//371
+f 1539//370 1540//370 1516//370
+f 1516//369 1540//369 1541//369
+f 1541//368 1542//368 1518//368
+f 1518//367 1542//367 1543//367
+f 1519//366 1543//366 1544//366
+f 1520//365 1544//365 1545//365
+f 1545//364 1546//364 1522//364
+f 1546//1167 1547//1167 1523//1167
+f 1523//362 1547//362 1548//362
+f 1524//361 1548//361 1549//361
+f 1549//384 1550//384 1526//384
+f 1550//383 1551//383 1527//383
+f 1551//382 1552//382 1528//382
+f 1552//381 1553//381 1529//381
+f 1553//380 1554//380 1530//380
+f 1554//379 1555//379 1531//379
+f 1555//378 1556//378 1532//378
+f 1556//377 1557//377 1533//377
+f 1557//376 1558//376 1534//376
+f 1534//375 1558//375 1559//375
+f 1559//374 1560//374 1536//374
+f 1536//373 1560//373 1537//373
+f 1537//396 1561//396 1562//396
+f 1562//395 1563//395 1539//395
+f 1563//394 1564//394 1540//394
+f 1540//393 1564//393 1565//393
+f 1565//392 1566//392 1542//392
+f 1566//391 1567//391 1543//391
+f 1567//390 1568//390 1544//390
+f 1568//389 1569//389 1545//389
+f 1569//388 1570//388 1546//388
+f 1570//387 1571//387 1547//387
+f 1547//386 1571//386 1572//386
+f 1548//385 1572//385 1573//385
+f 1573//408 1574//408 1550//408
+f 1574//407 1575//407 1551//407
+f 1551//406 1575//406 1576//406
+f 1552//405 1576//405 1577//405
+f 1553//404 1577//404 1578//404
+f 1554//403 1578//403 1579//403
+f 1579//402 1580//402 1556//402
+f 1556//401 1580//401 1581//401
+f 1581//400 1582//400 1558//400
+f 1558//399 1582//399 1583//399
+f 1559//398 1583//398 1584//398
+f 1560//397 1584//397 1561//397
+f 1561//420 1585//420 1586//420
+f 1586//419 1587//419 1563//419
+f 1563//418 1587//418 1588//418
+f 1564//417 1588//417 1589//417
+f 1565//416 1589//416 1590//416
+f 1590//415 1591//415 1567//415
+f 1591//414 1592//414 1568//414
+f 1592//413 1593//413 1569//413
+f 1569//412 1593//412 1594//412
+f 1594//411 1595//411 1571//411
+f 1571//410 1595//410 1596//410
+f 1572//409 1596//409 1597//409
+f 1597//432 1598//432 1574//432
+f 1598//431 1599//431 1575//431
+f 1575//430 1599//430 1600//430
+f 1576//429 1600//429 1601//429
+f 1577//428 1601//428 1602//428
+f 1602//427 1603//427 1579//427
+f 1579//426 1603//426 1604//426
+f 1604//425 1605//425 1581//425
+f 1605//424 1606//424 1582//424
+f 1606//423 1607//423 1583//423
+f 1583//422 1607//422 1608//422
+f 1584//421 1608//421 1585//421
+f 1609//444 1610//444 1586//444
+f 1610//443 1611//443 1587//443
+f 1587//442 1611//442 1612//442
+f 1612//441 1613//441 1589//441
+f 1589//440 1613//440 1614//440
+f 1614//439 1615//439 1591//439
+f 1591//438 1615//438 1616//438
+f 1592//437 1616//437 1617//437
+f 1593//436 1617//436 1618//436
+f 1618//1168 1619//1168 1595//1168
+f 1619//434 1620//434 1596//434
+f 1620//433 1621//433 1597//433
+f 1597//456 1621//456 1622//456
+f 1622//455 1623//455 1599//455
+f 1599//1169 1623//1169 1624//1169
+f 1624//453 1625//453 1601//453
+f 1625//452 1626//452 1602//452
+f 1626//451 1627//451 1603//451
+f 1627//450 1628//450 1604//450
+f 1604//449 1628//449 1629//449
+f 1605//448 1629//448 1630//448
+f 1630//447 1631//447 1607//447
+f 1607//446 1631//446 1632//446
+f 1608//445 1632//445 1609//445
+f 1609//468 1633//468 1634//468
+f 1634//467 1635//467 1611//467
+f 1611//466 1635//466 1636//466
+f 1636//465 1637//465 1613//465
+f 1637//464 1638//464 1614//464
+f 1614//463 1638//463 1639//463
+f 1639//462 1640//462 1616//462
+f 1616//461 1640//461 1641//461
+f 1641//460 1642//460 1618//460
+f 1618//459 1642//459 1643//459
+f 1643//458 1644//458 1620//458
+f 1644//457 1645//457 1621//457
+f 1621//480 1645//480 1646//480
+f 1646//479 1647//479 1623//479
+f 1647//478 1648//478 1624//478
+f 1648//477 1649//477 1625//477
+f 1649//476 1650//476 1626//476
+f 1626//475 1650//475 1651//475
+f 1651//474 1652//474 1628//474
+f 1628//473 1652//473 1653//473
+f 1653//472 1654//472 1630//472
+f 1654//471 1655//471 1631//471
+f 1631//470 1655//470 1656//470
+f 1656//469 1633//469 1609//469
+f 1657//492 1658//492 1634//492
+f 1658//491 1659//491 1635//491
+f 1635//490 1659//490 1660//490
+f 1636//489 1660//489 1661//489
+f 1661//488 1662//488 1638//488
+f 1662//487 1663//487 1639//487
+f 1639//486 1663//486 1664//486
+f 1640//485 1664//485 1665//485
+f 1665//484 1666//484 1642//484
+f 1666//483 1667//483 1643//483
+f 1643//482 1667//482 1668//482
+f 1644//481 1668//481 1669//481
+f 1669//504 1670//504 1646//504
+f 1670//503 1671//503 1647//503
+f 1671//502 1672//502 1648//502
+f 1648//501 1672//501 1673//501
+f 1673//500 1674//500 1650//500
+f 1674//499 1675//499 1651//499
+f 1651//498 1675//498 1676//498
+f 1652//497 1676//497 1677//497
+f 1677//496 1678//496 1654//496
+f 1678//495 1679//495 1655//495
+f 1655//494 1679//494 1680//494
+f 1680//493 1657//493 1633//493
+f 1681//516 1682//516 1658//516
+f 1682//515 1683//515 1659//515
+f 1683//514 1684//514 1660//514
+f 1684//513 1685//513 1661//513
+f 1685//512 1686//512 1662//512
+f 1662//511 1686//511 1687//511
+f 1687//510 1688//510 1664//510
+f 1664//509 1688//509 1689//509
+f 1689//508 1690//508 1666//508
+f 1690//507 1691//507 1667//507
+f 1691//506 1692//506 1668//506
+f 1692//505 1693//505 1669//505
+f 1669//528 1693//528 1694//528
+f 1670//527 1694//527 1695//527
+f 1695//526 1696//526 1672//526
+f 1672//525 1696//525 1697//525
+f 1697//524 1698//524 1674//524
+f 1674//523 1698//523 1699//523
+f 1699//522 1700//522 1676//522
+f 1676//521 1700//521 1701//521
+f 1677//520 1701//520 1702//520
+f 1678//519 1702//519 1703//519
+f 1679//518 1703//518 1704//518
+f 1680//517 1704//517 1681//517
+f 1705//540 1706//540 1682//540
+f 1682//539 1706//539 1707//539
+f 1683//538 1707//538 1708//538
+f 1708//537 1709//537 1685//537
+f 1685//536 1709//536 1710//536
+f 1710//535 1711//535 1687//535
+f 1711//534 1712//534 1688//534
+f 1688//533 1712//533 1713//533
+f 1713//532 1714//532 1690//532
+f 1690//531 1714//531 1715//531
+f 1715//530 1716//530 1692//530
+f 1716//529 1717//529 1693//529
+f 1693//552 1717//552 1718//552
+f 1694//551 1718//551 1719//551
+f 1719//550 1720//550 1696//550
+f 1720//549 1721//549 1697//549
+f 1721//548 1722//548 1698//548
+f 1698//547 1722//547 1723//547
+f 1699//546 1723//546 1724//546
+f 1724//545 1725//545 1701//545
+f 1701//544 1725//544 1726//544
+f 1726//543 1727//543 1703//543
+f 1727//542 1728//542 1704//542
+f 1704//541 1728//541 1705//541
+f 1729//1170 1730//1170 1706//1170
+f 1730//563 1731//563 1707//563
+f 1707//562 1731//562 1732//562
+f 1708//561 1732//561 1733//561
+f 1709//560 1733//560 1734//560
+f 1734//559 1735//559 1711//559
+f 1711//558 1735//558 1736//558
+f 1712//557 1736//557 1737//557
+f 1713//556 1737//556 1738//556
+f 1738//555 1739//555 1715//555
+f 1739//554 1740//554 1716//554
+f 1716//553 1740//553 1741//553
+f 1741//576 1742//576 1718//576
+f 1718//575 1742//575 1743//575
+f 1743//574 1744//574 1720//574
+f 1720//573 1744//573 1745//573
+f 1745//572 1746//572 1722//572
+f 1746//571 1747//571 1723//571
+f 1723//570 1747//570 1748//570
+f 1748//569 1749//569 1725//569
+f 1749//568 1750//568 1726//568
+f 1750//567 1751//567 1727//567
+f 1727//566 1751//566 1752//566
+f 1728//1171 1752//1171 1729//1171
+f 1753//588 1754//588 1730//588
+f 1754//587 1755//587 1731//587
+f 1731//586 1755//586 1756//586
+f 1756//585 1757//585 1733//585
+f 1757//584 1758//584 1734//584
+f 1758//583 1759//583 1735//583
+f 1759//582 1760//582 1736//582
+f 1760//581 1761//581 1737//581
+f 1761//580 1762//580 1738//580
+f 1738//579 1762//579 1763//579
+f 1763//578 1764//578 1740//578
+f 1740//577 1764//577 1765//577
+f 1765//600 1766//600 1742//600
+f 1742//599 1766//599 1767//599
+f 1767//598 1768//598 1744//598
+f 1744//597 1768//597 1769//597
+f 1745//596 1769//596 1770//596
+f 1746//595 1770//595 1771//595
+f 1747//594 1771//594 1772//594
+f 1772//593 1773//593 1749//593
+f 1749//592 1773//592 1774//592
+f 1774//591 1775//591 1751//591
+f 1751//590 1775//590 1776//590
+f 1776//589 1753//589 1729//589
+f 1777//612 1778//612 1754//612
+f 1778//611 1779//611 1755//611
+f 1779//610 1780//610 1756//610
+f 1756//609 1780//609 1781//609
+f 1781//608 1782//608 1758//608
+f 1758//607 1782//607 1783//607
+f 1783//606 1784//606 1760//606
+f 1760//605 1784//605 1785//605
+f 1761//604 1785//604 1786//604
+f 1786//603 1787//603 1763//603
+f 1787//602 1788//602 1764//602
+f 1764//601 1788//601 1789//601
+f 1789//624 1790//624 1766//624
+f 1766//623 1790//623 1791//623
+f 1767//622 1791//622 1792//622
+f 1792//621 1793//621 1769//621
+f 1793//620 1794//620 1770//620
+f 1770//619 1794//619 1795//619
+f 1795//618 1796//618 1772//618
+f 1796//617 1797//617 1773//617
+f 1797//616 1798//616 1774//616
+f 1798//615 1799//615 1775//615
+f 1775//614 1799//614 1800//614
+f 1776//613 1800//613 1777//613
+f 1777//636 1801//636 1802//636
+f 1802//635 1803//635 1779//635
+f 1803//634 1804//634 1780//634
+f 1780//633 1804//633 1805//633
+f 1781//632 1805//632 1806//632
+f 1782//1172 1806//1172 1807//1172
+f 1807//630 1808//630 1784//630
+f 1808//629 1809//629 1785//629
+f 1809//628 1810//628 1786//628
+f 1786//627 1810//627 1811//627
+f 1811//626 1812//626 1788//626
+f 1788//625 1812//625 1813//625
+f 1813//648 1814//648 1790//648
+f 1814//647 1815//647 1791//647
+f 1815//646 1816//646 1792//646
+f 1816//645 1817//645 1793//645
+f 1793//644 1817//644 1818//644
+f 1818//643 1819//643 1795//643
+f 1819//642 1820//642 1796//642
+f 1820//641 1821//641 1797//641
+f 1821//640 1822//640 1798//640
+f 1798//639 1822//639 1823//639
+f 1799//638 1823//638 1824//638
+f 1824//637 1801//637 1777//637
+f 1801//660 1825//660 1826//660
+f 1826//659 1827//659 1803//659
+f 1827//658 1828//658 1804//658
+f 1804//657 1828//657 1829//657
+f 1829//656 1830//656 1806//656
+f 1830//655 1831//655 1807//655
+f 1831//654 1832//654 1808//654
+f 1832//653 1833//653 1809//653
+f 1833//652 1834//652 1810//652
+f 1834//651 1835//651 1811//651
+f 1835//650 1836//650 1812//650
+f 1836//649 1837//649 1813//649
+f 1813//672 1837//672 1838//672
+f 1814//671 1838//671 1839//671
+f 1815//670 1839//670 1840//670
+f 1816//669 1840//669 1841//669
+f 1817//668 1841//668 1842//668
+f 1818//667 1842//667 1843//667
+f 1819//666 1843//666 1844//666
+f 1820//665 1844//665 1845//665
+f 1845//664 1846//664 1822//664
+f 1822//663 1846//663 1847//663
+f 1823//662 1847//662 1848//662
+f 1848//661 1825//661 1801//661
+f 1825//684 1849//684 1850//684
+f 1850//683 1851//683 1827//683
+f 1851//682 1852//682 1828//682
+f 1828//681 1852//681 1853//681
+f 1829//680 1853//680 1854//680
+f 1830//679 1854//679 1855//679
+f 1831//678 1855//678 1856//678
+f 1856//677 1857//677 1833//677
+f 1833//676 1857//676 1858//676
+f 1834//675 1858//675 1859//675
+f 1859//674 1860//674 1836//674
+f 1860//673 1861//673 1837//673
+f 1837//696 1861//696 1862//696
+f 1838//695 1862//695 1863//695
+f 1863//694 1864//694 1840//694
+f 1864//693 1865//693 1841//693
+f 1841//692 1865//692 1866//692
+f 1866//691 1867//691 1843//691
+f 1843//690 1867//690 1868//690
+f 1868//689 1869//689 1845//689
+f 1869//688 1870//688 1846//688
+f 1846//687 1870//687 1871//687
+f 1847//686 1871//686 1872//686
+f 1872//685 1849//685 1825//685
+f 1873//708 1874//708 1850//708
+f 1874//707 1875//707 1851//707
+f 1875//1173 1876//1173 1852//1173
+f 1876//705 1877//705 1853//705
+f 1853//704 1877//704 1878//704
+f 1878//703 1879//703 1855//703
+f 1855//702 1879//702 1880//702
+f 1880//701 1881//701 1857//701
+f 1881//700 1882//700 1858//700
+f 1882//1174 1883//1174 1859//1174
+f 1883//698 1884//698 1860//698
+f 1860//697 1884//697 1885//697
+f 1885//720 1886//720 1862//720
+f 1862//719 1886//719 1887//719
+f 1863//1175 1887//1175 1888//1175
+f 1864//717 1888//717 1889//717
+f 1865//716 1889//716 1890//716
+f 1890//715 1891//715 1867//715
+f 1867//714 1891//714 1892//714
+f 1892//713 1893//713 1869//713
+f 1869//712 1893//712 1894//712
+f 1870//1176 1894//1176 1895//1176
+f 1895//710 1896//710 1872//710
+f 1896//709 1873//709 1849//709
+f 1897//732 1898//732 1874//732
+f 1874//731 1898//731 1899//731
+f 1875//730 1899//730 1900//730
+f 1876//729 1900//729 1901//729
+f 1877//728 1901//728 1902//728
+f 1878//727 1902//727 1903//727
+f 1879//726 1903//726 1904//726
+f 1880//725 1904//725 1905//725
+f 1905//724 1906//724 1882//724
+f 1882//723 1906//723 1907//723
+f 1883//722 1907//722 1908//722
+f 1908//721 1909//721 1885//721
+f 1909//744 1910//744 1886//744
+f 1910//743 1911//743 1887//743
+f 1911//742 1912//742 1888//742
+f 1912//741 1913//741 1889//741
+f 1913//740 1914//740 1890//740
+f 1914//739 1915//739 1891//739
+f 1915//738 1916//738 1892//738
+f 1916//737 1917//737 1893//737
+f 1917//736 1918//736 1894//736
+f 1894//735 1918//735 1919//735
+f 1919//734 1920//734 1896//734
+f 1896//733 1920//733 1897//733
+f 1921//756 1922//756 1898//756
+f 1898//755 1922//755 1923//755
+f 1923//754 1924//754 1900//754
+f 1924//753 1925//753 1901//753
+f 1925//752 1926//752 1902//752
+f 1926//751 1927//751 1903//751
+f 1927//750 1928//750 1904//750
+f 1904//1177 1928//1177 1929//1177
+f 1929//748 1930//748 1906//748
+f 1906//747 1930//747 1931//747
+f 1931//746 1932//746 1908//746
+f 1908//745 1932//745 1933//745
+f 1933//768 1934//768 1910//768
+f 1910//767 1934//767 1935//767
+f 1935//766 1936//766 1912//766
+f 1912//765 1936//765 1937//765
+f 1937//1178 1938//1178 1914//1178
+f 1914//763 1938//763 1939//763
+f 1915//762 1939//762 1940//762
+f 1940//761 1941//761 1917//761
+f 1917//760 1941//760 1942//760
+f 1918//759 1942//759 1943//759
+f 1943//758 1944//758 1920//758
+f 1920//757 1944//757 1921//757
+f 1921//780 1945//780 1946//780
+f 1922//779 1946//779 1947//779
+f 1923//1179 1947//1179 1948//1179
+f 1924//777 1948//777 1949//777
+f 1949//776 1950//776 1926//776
+f 1926//775 1950//775 1951//775
+f 1927//774 1951//774 1952//774
+f 1952//773 1953//773 1929//773
+f 1929//772 1953//772 1954//772
+f 1930//771 1954//771 1955//771
+f 1955//770 1956//770 1932//770
+f 1932//769 1956//769 1957//769
+f 1957//792 1958//792 1934//792
+f 1934//791 1958//791 1959//791
+f 1959//790 1960//790 1936//790
+f 1960//789 1961//789 1937//789
+f 1961//788 1962//788 1938//788
+f 1962//787 1963//787 1939//787
+f 1963//786 1964//786 1940//786
+f 1940//785 1964//785 1965//785
+f 1965//784 1966//784 1942//784
+f 1966//1180 1967//1180 1943//1180
+f 1967//782 1968//782 1944//782
+f 1968//781 1945//781 1921//781
+f 1969//804 1970//804 1946//804
+f 1946//803 1970//803 1971//803
+f 1971//802 1972//802 1948//802
+f 1948//801 1972//801 1973//801
+f 1973//800 1974//800 1950//800
+f 1974//799 1975//799 1951//799
+f 1951//798 1975//798 1976//798
+f 1952//797 1976//797 1977//797
+f 1977//796 1978//796 1954//796
+f 1954//795 1978//795 1979//795
+f 1979//794 1980//794 1956//794
+f 1980//793 1981//793 1957//793
+f 1957//816 1981//816 1982//816
+f 1958//815 1982//815 1983//815
+f 1983//814 1984//814 1960//814
+f 1984//813 1985//813 1961//813
+f 1985//812 1986//812 1962//812
+f 1986//811 1987//811 1963//811
+f 1963//810 1987//810 1988//810
+f 1988//809 1989//809 1965//809
+f 1989//808 1990//808 1966//808
+f 1966//807 1990//807 1991//807
+f 1991//806 1992//806 1968//806
+f 1968//805 1992//805 1969//805
+f 1993//828 1994//828 1970//828
+f 1970//1181 1994//1181 1995//1181
+f 1995//826 1996//826 1972//826
+f 1996//825 1997//825 1973//825
+f 1973//824 1997//824 1998//824
+f 1974//823 1998//823 1999//823
+f 1999//822 2000//822 1976//822
+f 2000//821 2001//821 1977//821
+f 2001//820 2002//820 1978//820
+f 2002//819 2003//819 1979//819
+f 2003//818 2004//818 1980//818
+f 2004//817 2005//817 1981//817
+f 1981//840 2005//840 2006//840
+f 1982//839 2006//839 2007//839
+f 1983//838 2007//838 2008//838
+f 1984//837 2008//837 2009//837
+f 2009//836 2010//836 1986//836
+f 1986//835 2010//835 2011//835
+f 2011//834 2012//834 1988//834
+f 2012//833 2013//833 1989//833
+f 1989//832 2013//832 2014//832
+f 1990//831 2014//831 2015//831
+f 2015//1182 2016//1182 1992//1182
+f 2016//829 1993//829 1969//829
+f 2017//1183 2018//1183 1994//1183
+f 1994//851 2018//851 2019//851
+f 2019//850 2020//850 1996//850
+f 1996//849 2020//849 2021//849
+f 2021//848 2022//848 1998//848
+f 1998//847 2022//847 2023//847
+f 1999//846 2023//846 2024//846
+f 2000//845 2024//845 2025//845
+f 2001//844 2025//844 2026//844
+f 2026//843 2027//843 2003//843
+f 2003//842 2027//842 2028//842
+f 2028//841 2029//841 2005//841
+f 2005//1184 2029//1184 2030//1184
+f 2030//863 2031//863 2007//863
+f 2031//862 2032//862 2008//862
+f 2032//861 2033//861 2009//861
+f 2033//860 2034//860 2010//860
+f 2034//859 2035//859 2011//859
+f 2011//858 2035//858 2036//858
+f 2012//857 2036//857 2037//857
+f 2037//856 2038//856 2014//856
+f 2014//855 2038//855 2039//855
+f 2039//854 2040//854 2016//854
+f 2040//853 2017//853 1993//853
+f 2041//876 2042//876 2018//876
+f 2018//875 2042//875 2043//875
+f 2043//874 2044//874 2020//874
+f 2020//873 2044//873 2045//873
+f 2045//872 2046//872 2022//872
+f 2046//871 2047//871 2023//871
+f 2023//870 2047//870 2048//870
+f 2024//869 2048//869 2049//869
+f 2049//868 2050//868 2026//868
+f 2050//867 2051//867 2027//867
+f 2027//866 2051//866 2052//866
+f 2052//865 2053//865 2029//865
+f 2029//888 2053//888 2054//888
+f 2054//887 2055//887 2031//887
+f 2031//886 2055//886 2056//886
+f 2056//885 2057//885 2033//885
+f 2057//884 2058//884 2034//884
+f 2034//883 2058//883 2059//883
+f 2059//882 2060//882 2036//882
+f 2036//881 2060//881 2061//881
+f 2061//880 2062//880 2038//880
+f 2038//879 2062//879 2063//879
+f 2063//878 2064//878 2040//878
+f 2040//877 2064//877 2041//877
+f 2065//900 2066//900 2042//900
+f 2042//1185 2066//1185 2067//1185
+f 2067//898 2068//898 2044//898
+f 2068//897 2069//897 2045//897
+f 2045//896 2069//896 2070//896
+f 2070//895 2071//895 2047//895
+f 2071//894 2072//894 2048//894
+f 2048//893 2072//893 2073//893
+f 2073//892 2074//892 2050//892
+f 2050//891 2074//891 2075//891
+f 2075//890 2076//890 2052//890
+f 2076//889 2077//889 2053//889
+f 2053//912 2077//912 2078//912
+f 2054//911 2078//911 2079//911
+f 2079//910 2080//910 2056//910
+f 2056//909 2080//909 2081//909
+f 2081//908 2082//908 2058//908
+f 2058//907 2082//907 2083//907
+f 2059//906 2083//906 2084//906
+f 2084//905 2085//905 2061//905
+f 2085//904 2086//904 2062//904
+f 2062//903 2086//903 2087//903
+f 2087//902 2088//902 2064//902
+f 2088//901 2065//901 2041//901
+f 2089//924 2090//924 2066//924
+f 2066//923 2090//923 2091//923
+f 2091//922 2092//922 2068//922
+f 2068//921 2092//921 2093//921
+f 2069//920 2093//920 2094//920
+f 2070//919 2094//919 2095//919
+f 2095//918 2096//918 2072//918
+f 2096//917 2097//917 2073//917
+f 2097//916 2098//916 2074//916
+f 2098//915 2099//915 2075//915
+f 2075//914 2099//914 2100//914
+f 2100//913 2101//913 2077//913
+f 2101//936 2102//936 2078//936
+f 2102//935 2103//935 2079//935
+f 2079//934 2103//934 2104//934
+f 2080//933 2104//933 2105//933
+f 2081//932 2105//932 2106//932
+f 2082//931 2106//931 2107//931
+f 2107//930 2108//930 2084//930
+f 2108//929 2109//929 2085//929
+f 2109//928 2110//928 2086//928
+f 2086//927 2110//927 2111//927
+f 2111//926 2112//926 2088//926
+f 2088//925 2112//925 2089//925
+f 2089//948 2113//948 2114//948
+f 2090//947 2114//947 2115//947
+f 2115//1186 2116//1186 2092//1186
+f 2116//945 2117//945 2093//945
+f 2117//944 2118//944 2094//944
+f 2118//943 2119//943 2095//943
+f 2119//942 2120//942 2096//942
+f 2120//941 2121//941 2097//941
+f 2097//940 2121//940 2122//940
+f 2098//1187 2122//1187 2123//1187
+f 2099//938 2123//938 2124//938
+f 2124//937 2125//937 2101//937
+f 2101//960 2125//960 2126//960
+f 2126//959 2127//959 2103//959
+f 2127//958 2128//958 2104//958
+f 2128//957 2129//957 2105//957
+f 2105//956 2129//956 2130//956
+f 2106//955 2130//955 2131//955
+f 2107//954 2131//954 2132//954
+f 2108//953 2132//953 2133//953
+f 2109//952 2133//952 2134//952
+f 2110//1188 2134//1188 2135//1188
+f 2135//950 2136//950 2112//950
+f 2136//949 2113//949 2089//949
+f 2113//972 2137//972 2138//972
+f 2138//971 2139//971 2115//971
+f 2115//970 2139//970 2140//970
+f 2116//969 2140//969 2141//969
+f 2141//968 2142//968 2118//968
+f 2142//967 2143//967 2119//967
+f 2119//966 2143//966 2144//966
+f 2144//965 2145//965 2121//965
+f 2145//964 2146//964 2122//964
+f 2146//963 2147//963 2123//963
+f 2147//962 2148//962 2124//962
+f 2124//961 2148//961 2149//961
+f 2149//984 2150//984 2126//984
+f 2150//983 2151//983 2127//983
+f 2127//982 2151//982 2152//982
+f 2128//981 2152//981 2153//981
+f 2129//980 2153//980 2154//980
+f 2154//979 2155//979 2131//979
+f 2131//978 2155//978 2156//978
+f 2156//1189 2157//1189 2133//1189
+f 2157//976 2158//976 2134//976
+f 2158//975 2159//975 2135//975
+f 2159//974 2160//974 2136//974
+f 2160//973 2137//973 2113//973
+f 2137//996 2161//996 2162//996
+f 2162//995 2163//995 2139//995
+f 2163//994 2164//994 2140//994
+f 2164//993 2165//993 2141//993
+f 2165//992 2166//992 2142//992
+f 2166//991 2167//991 2143//991
+f 2167//990 2168//990 2144//990
+f 2168//989 2169//989 2145//989
+f 2145//988 2169//988 2170//988
+f 2170//987 2171//987 2147//987
+f 2147//986 2171//986 2172//986
+f 2148//985 2172//985 2173//985
+f 2173//1008 2174//1008 2150//1008
+f 2174//1007 2175//1007 2151//1007
+f 2151//1006 2175//1006 2176//1006
+f 2176//1005 2177//1005 2153//1005
+f 2153//1004 2177//1004 2178//1004
+f 2154//1003 2178//1003 2179//1003
+f 2155//1002 2179//1002 2180//1002
+f 2180//1001 2181//1001 2157//1001
+f 2157//1000 2181//1000 2182//1000
+f 2182//999 2183//999 2159//999
+f 2159//998 2183//998 2184//998
+f 2184//997 2161//997 2137//997
+f 2161//1020 2185//1020 2186//1020
+f 2186//1019 2187//1019 2163//1019
+f 2163//1190 2187//1190 2188//1190
+f 2188//1017 2189//1017 2165//1017
+f 2165//1016 2189//1016 2190//1016
+f 2166//1015 2190//1015 2191//1015
+f 2167//1014 2191//1014 2192//1014
+f 2168//1013 2192//1013 2193//1013
+f 2169//1012 2193//1012 2194//1012
+f 2194//1191 2195//1191 2171//1191
+f 2195//1010 2196//1010 2172//1010
+f 2196//1009 2197//1009 2173//1009
+f 2173//1032 2197//1032 2198//1032
+f 2198//1031 2199//1031 2175//1031
+f 2199//1192 2200//1192 2176//1192
+f 2200//1029 2201//1029 2177//1029
+f 2201//1028 2202//1028 2178//1028
+f 2202//1027 2203//1027 2179//1027
+f 2203//1026 2204//1026 2180//1026
+f 2204//1025 2205//1025 2181//1025
+f 2205//1024 2206//1024 2182//1024
+f 2206//1193 2207//1193 2183//1193
+f 2183//1022 2207//1022 2208//1022
+f 2208//1021 2185//1021 2161//1021
+f 2185//1044 2209//1044 2210//1044
+f 2210//1043 2211//1043 2187//1043
+f 2211//1042 2212//1042 2188//1042
+f 2212//1041 2213//1041 2189//1041
+f 2213//1040 2214//1040 2190//1040
+f 2214//1039 2215//1039 2191//1039
+f 2215//1038 2216//1038 2192//1038
+f 2192//1037 2216//1037 2217//1037
+f 2193//1036 2217//1036 2218//1036
+f 2218//1035 2219//1035 2195//1035
+f 2195//1034 2219//1034 2220//1034
+f 2220//1033 2221//1033 2197//1033
+f 2197//1056 2221//1056 2222//1056
+f 2222//1055 2223//1055 2199//1055
+f 2199//1054 2223//1054 2224//1054
+f 2224//1053 2225//1053 2201//1053
+f 2201//1052 2225//1052 2226//1052
+f 2202//1051 2226//1051 2227//1051
+f 2203//1050 2227//1050 2228//1050
+f 2204//1049 2228//1049 2229//1049
+f 2229//1048 2230//1048 2206//1048
+f 2206//1047 2230//1047 2231//1047
+f 2207//1046 2231//1046 2232//1046
+f 2232//1045 2209//1045 2185//1045
+f 2209//1068 2233//1068 2234//1068
+f 2210//1067 2234//1067 2235//1067
+f 2235//1066 2236//1066 2212//1066
+f 2212//1065 2236//1065 2237//1065
+f 2237//1064 2238//1064 2214//1064
+f 2238//1063 2239//1063 2215//1063
+f 2239//1062 2240//1062 2216//1062
+f 2240//1061 2241//1061 2217//1061
+f 2241//1060 2242//1060 2218//1060
+f 2242//1059 2243//1059 2219//1059
+f 2243//1058 2244//1058 2220//1058
+f 2244//1057 2245//1057 2221//1057
+f 2245//1080 2246//1080 2222//1080
+f 2222//1079 2246//1079 2247//1079
+f 2223//1078 2247//1078 2248//1078
+f 2248//1077 2249//1077 2225//1077
+f 2225//1076 2249//1076 2250//1076
+f 2250//1075 2251//1075 2227//1075
+f 2227//1074 2251//1074 2252//1074
+f 2228//1073 2252//1073 2253//1073
+f 2229//1072 2253//1072 2254//1072
+f 2230//1071 2254//1071 2255//1071
+f 2255//1070 2256//1070 2232//1070
+f 2256//1069 2233//1069 2209//1069
+f 2257//1092 2258//1092 2234//1092
+f 2258//1091 2259//1091 2235//1091
+f 2235//1090 2259//1090 2260//1090
+f 2236//1089 2260//1089 2261//1089
+f 2237//1088 2261//1088 2262//1088
+f 2238//1087 2262//1087 2263//1087
+f 2263//1086 2264//1086 2240//1086
+f 2240//1085 2264//1085 2265//1085
+f 2241//1084 2265//1084 2266//1084
+f 2266//1083 2267//1083 2243//1083
+f 2267//1082 2268//1082 2244//1082
+f 2244//1081 2268//1081 2269//1081
+f 2269//1104 2270//1104 2246//1104
+f 2270//1103 2271//1103 2247//1103
+f 2271//1102 2272//1102 2248//1102
+f 2248//1101 2272//1101 2273//1101
+f 2273//1100 2274//1100 2250//1100
+f 2250//1099 2274//1099 2275//1099
+f 2275//1098 2276//1098 2252//1098
+f 2276//1097 2277//1097 2253//1097
+f 2277//1096 2278//1096 2254//1096
+f 2278//1095 2279//1095 2255//1095
+f 2255//1094 2279//1094 2280//1094
+f 2256//1093 2280//1093 2257//1093
+f 2257//1116 2281//1116 2282//1116
+f 2282//1115 2283//1115 2259//1115
+f 2283//1114 2284//1114 2260//1114
+f 2284//1113 2285//1113 2261//1113
+f 2285//1112 2286//1112 2262//1112
+f 2286//1111 2287//1111 2263//1111
+f 2287//1110 2288//1110 2264//1110
+f 2288//1109 2289//1109 2265//1109
+f 2289//1108 2290//1108 2266//1108
+f 2290//1107 2291//1107 2267//1107
+f 2291//1106 2292//1106 2268//1106
+f 2292//1105 2293//1105 2269//1105
+f 2269//1128 2293//1128 2294//1128
+f 2270//1127 2294//1127 2295//1127
+f 2271//1126 2295//1126 2296//1126
+f 2272//1125 2296//1125 2297//1125
+f 2273//1124 2297//1124 2298//1124
+f 2274//1123 2298//1123 2299//1123
+f 2275//1122 2299//1122 2300//1122
+f 2276//1121 2300//1121 2301//1121
+f 2277//1120 2301//1120 2302//1120
+f 2302//1119 2303//1119 2279//1119
+f 2279//1118 2303//1118 2304//1118
+f 2304//1117 2281//1117 2257//1117
+f 1//1140 2//1140 2282//1140
+f 2//1139 3//1139 2283//1139
+f 3//1138 4//1138 2284//1138
+f 4//1137 5//1137 2285//1137
+f 5//1136 6//1136 2286//1136
+f 6//1135 7//1135 2287//1135
+f 2287//1134 7//1134 8//1134
+f 8//1133 9//1133 2289//1133
+f 9//1132 10//1132 2290//1132
+f 2290//1131 10//1131 11//1131
+f 2291//1130 11//1130 12//1130
+f 2292//1129 12//1129 13//1129
+f 13//1152 14//1152 2294//1152
+f 14//1151 15//1151 2295//1151
+f 15//1150 16//1150 2296//1150
+f 2296//1149 16//1149 17//1149
+f 2297//1148 17//1148 18//1148
+f 18//1147 19//1147 2299//1147
+f 19//1146 20//1146 2300//1146
+f 20//1145 21//1145 2301//1145
+f 21//1144 22//1144 2302//1144
+f 2302//1143 22//1143 23//1143
+f 23//1142 24//1142 2304//1142
+f 24//1141 1//1141 2281//1141
+f 1//1 25//1 2//1
+f 2//2 26//2 3//2
+f 4//3 3//3 28//3
+f 4//4 28//4 5//4
+f 6//5 5//5 30//5
+f 6//6 30//6 7//6
+f 7//7 31//7 8//7
+f 8//8 32//8 9//8
+f 10//9 9//9 34//9
+f 10//10 34//10 11//10
+f 11//11 35//11 12//11
+f 12//12 36//12 13//12
+f 14//13 13//13 38//13
+f 15//14 14//14 39//14
+f 15//15 39//15 16//15
+f 16//16 40//16 17//16
+f 17//17 41//17 18//17
+f 19//18 18//18 43//18
+f 20//19 19//19 44//19
+f 20//20 44//20 21//20
+f 21//21 45//21 22//21
+f 22//22 46//22 23//22
+f 24//23 23//23 48//23
+f 1//24 24//24 25//24
+f 25//25 49//25 26//25
+f 27//26 26//26 51//26
+f 28//27 27//27 52//27
+f 29//28 28//28 53//28
+f 30//29 29//29 54//29
+f 30//30 54//30 31//30
+f 32//31 31//31 56//31
+f 33//32 32//32 57//32
+f 34//33 33//33 58//33
+f 35//34 34//34 59//34
+f 36//35 35//35 60//35
+f 37//36 36//36 61//36
+f 37//37 61//37 38//37
+f 38//38 62//38 39//38
+f 39//39 63//39 40//39
+f 40//40 64//40 41//40
+f 41//41 65//41 42//41
+f 42//42 66//42 43//42
+f 43//43 67//43 44//43
+f 44//44 68//44 45//44
+f 45//45 69//45 46//45
+f 46//46 70//46 47//46
+f 47//47 71//47 48//47
+f 25//48 48//48 49//48
+f 49//49 73//49 50//49
+f 51//50 50//50 75//50
+f 51//51 75//51 52//51
+f 52//52 76//52 53//52
+f 53//53 77//53 54//53
+f 55//1154 54//1154 79//1154
+f 55//1153 79//1153 56//1153
+f 56//56 80//56 57//56
+f 57//57 81//57 58//57
+f 58//58 82//58 59//58
+f 60//59 59//59 84//59
+f 61//60 60//60 85//60
+f 61//61 85//61 62//61
+f 62//62 86//62 63//62
+f 63//63 87//63 64//63
+f 65//64 64//64 89//64
+f 65//65 89//65 66//65
+f 66//1194 90//1194 67//1194
+f 68//1195 67//1195 92//1195
+f 69//68 68//68 93//68
+f 70//69 69//69 94//69
+f 71//70 70//70 95//70
+f 71//71 95//71 72//71
+f 72//72 96//72 49//72
+f 73//73 97//73 74//73
+f 74//74 98//74 75//74
+f 76//75 75//75 100//75
+f 77//76 76//76 101//76
+f 78//77 77//77 102//77
+f 79//78 78//78 103//78
+f 80//79 79//79 104//79
+f 81//80 80//80 105//80
+f 82//81 81//81 106//81
+f 82//82 106//82 83//82
+f 84//83 83//83 108//83
+f 84//84 108//84 85//84
+f 86//85 85//85 110//85
+f 86//86 110//86 87//86
+f 88//87 87//87 112//87
+f 88//88 112//88 89//88
+f 89//89 113//89 90//89
+f 90//90 114//90 91//90
+f 91//91 115//91 92//91
+f 92//92 116//92 93//92
+f 93//93 117//93 94//93
+f 94//94 118//94 95//94
+f 96//95 95//95 120//95
+f 96//96 120//96 73//96
+f 97//97 121//97 98//97
+f 99//98 98//98 123//98
+f 99//99 123//99 100//99
+f 100//100 124//100 101//100
+f 101//101 125//101 102//101
+f 102//102 126//102 103//102
+f 103//103 127//103 104//103
+f 104//104 128//104 105//104
+f 105//105 129//105 106//105
+f 106//106 130//106 107//106
+f 107//107 131//107 108//107
+f 108//108 132//108 109//108
+f 109//109 133//109 110//109
+f 111//110 110//110 135//110
+f 112//111 111//111 136//111
+f 113//112 112//112 137//112
+f 114//113 113//113 138//113
+f 115//114 114//114 139//114
+f 116//115 115//115 140//115
+f 117//116 116//116 141//116
+f 118//117 117//117 142//117
+f 119//118 118//118 143//118
+f 119//119 143//119 120//119
+f 97//120 120//120 121//120
+f 121//121 145//121 122//121
+f 123//122 122//122 147//122
+f 124//123 123//123 148//123
+f 125//124 124//124 149//124
+f 126//125 125//125 150//125
+f 126//126 150//126 127//126
+f 128//127 127//127 152//127
+f 128//128 152//128 129//128
+f 129//129 153//129 130//129
+f 131//130 130//130 155//130
+f 131//131 155//131 132//131
+f 133//132 132//132 157//132
+f 133//133 157//133 134//133
+f 134//134 158//134 135//134
+f 135//135 159//135 136//135
+f 136//136 160//136 137//136
+f 138//137 137//137 162//137
+f 138//138 162//138 139//138
+f 139//139 163//139 140//139
+f 140//140 164//140 141//140
+f 141//141 165//141 142//141
+f 142//142 166//142 143//142
+f 143//143 167//143 144//143
+f 144//144 168//144 121//144
+f 145//145 169//145 146//145
+f 146//146 170//146 147//146
+f 148//147 147//147 172//147
+f 148//148 172//148 149//148
+f 149//149 173//149 150//149
+f 150//150 174//150 151//150
+f 151//151 175//151 152//151
+f 152//152 176//152 153//152
+f 153//153 177//153 154//153
+f 154//154 178//154 155//154
+f 155//155 179//155 156//155
+f 156//156 180//156 157//156
+f 158//157 157//157 182//157
+f 159//158 158//158 183//158
+f 160//159 159//159 184//159
+f 161//160 160//160 185//160
+f 162//161 161//161 186//161
+f 163//162 162//162 187//162
+f 163//163 187//163 164//163
+f 165//164 164//164 189//164
+f 166//165 165//165 190//165
+f 166//166 190//166 167//166
+f 168//167 167//167 192//167
+f 145//168 168//168 169//168
+f 169//169 193//169 170//169
+f 171//1155 170//1155 195//1155
+f 172//171 171//171 196//171
+f 173//172 172//172 197//172
+f 174//1196 173//1196 198//1196
+f 175//174 174//174 199//174
+f 175//175 199//175 176//175
+f 177//176 176//176 201//176
+f 177//177 201//177 178//177
+f 179//178 178//178 203//178
+f 180//179 179//179 204//179
+f 180//180 204//180 181//180
+f 182//181 181//181 206//181
+f 182//182 206//182 183//182
+f 183//183 207//183 184//183
+f 184//184 208//184 185//184
+f 185//185 209//185 186//185
+f 186//186 210//186 187//186
+f 188//187 187//187 212//187
+f 188//188 212//188 189//188
+f 189//189 213//189 190//189
+f 190//190 214//190 191//190
+f 191//191 215//191 192//191
+f 192//192 216//192 169//192
+f 193//193 217//193 194//193
+f 194//194 218//194 195//194
+f 196//1156 195//1156 220//1156
+f 196//196 220//196 197//196
+f 198//197 197//197 222//197
+f 199//198 198//198 223//198
+f 200//199 199//199 224//199
+f 200//200 224//200 201//200
+f 201//201 225//201 202//201
+f 202//202 226//202 203//202
+f 203//203 227//203 204//203
+f 205//204 204//204 229//204
+f 205//205 229//205 206//205
+f 207//206 206//206 231//206
+f 208//207 207//207 232//207
+f 209//208 208//208 233//208
+f 209//209 233//209 210//209
+f 210//210 234//210 211//210
+f 211//211 235//211 212//211
+f 212//212 236//212 213//212
+f 213//213 237//213 214//213
+f 214//1157 238//1157 215//1157
+f 216//215 215//215 240//215
+f 193//216 216//216 217//216
+f 217//217 241//217 218//217
+f 218//218 242//218 219//218
+f 220//219 219//219 244//219
+f 220//220 244//220 221//220
+f 221//221 245//221 222//221
+f 222//222 246//222 223//222
+f 224//223 223//223 248//223
+f 225//224 224//224 249//224
+f 226//225 225//225 250//225
+f 227//226 226//226 251//226
+f 228//227 227//227 252//227
+f 228//228 252//228 229//228
+f 229//229 253//229 230//229
+f 231//230 230//230 255//230
+f 231//231 255//231 232//231
+f 232//232 256//232 233//232
+f 234//233 233//233 258//233
+f 234//234 258//234 235//234
+f 236//235 235//235 260//235
+f 237//236 236//236 261//236
+f 238//237 237//237 262//237
+f 238//238 262//238 239//238
+f 240//239 239//239 264//239
+f 240//240 264//240 217//240
+f 242//241 241//241 266//241
+f 242//242 266//242 243//242
+f 243//243 267//243 244//243
+f 244//244 268//244 245//244
+f 245//245 269//245 246//245
+f 247//246 246//246 271//246
+f 247//247 271//247 248//247
+f 248//248 272//248 249//248
+f 250//249 249//249 274//249
+f 250//250 274//250 251//250
+f 251//251 275//251 252//251
+f 252//252 276//252 253//252
+f 254//253 253//253 278//253
+f 254//254 278//254 255//254
+f 256//255 255//255 280//255
+f 256//256 280//256 257//256
+f 258//257 257//257 282//257
+f 259//258 258//258 283//258
+f 259//259 283//259 260//259
+f 261//260 260//260 285//260
+f 262//261 261//261 286//261
+f 262//262 286//262 263//262
+f 263//263 287//263 264//263
+f 264//264 288//264 241//264
+f 266//265 265//265 290//265
+f 266//266 290//266 267//266
+f 268//267 267//267 292//267
+f 268//268 292//268 269//268
+f 269//269 293//269 270//269
+f 270//270 294//270 271//270
+f 271//271 295//271 272//271
+f 272//272 296//272 273//272
+f 274//273 273//273 298//273
+f 274//274 298//274 275//274
+f 275//275 299//275 276//275
+f 276//1158 300//1158 277//1158
+f 277//277 301//277 278//277
+f 279//278 278//278 303//278
+f 280//279 279//279 304//279
+f 280//280 304//280 281//280
+f 281//281 305//281 282//281
+f 283//282 282//282 307//282
+f 284//283 283//283 308//283
+f 284//284 308//284 285//284
+f 286//285 285//285 310//285
+f 286//286 310//286 287//286
+f 287//287 311//287 288//287
+f 288//288 312//288 265//288
+f 290//1197 289//1197 314//1197
+f 290//290 314//290 291//290
+f 292//291 291//291 316//291
+f 293//292 292//292 317//292
+f 294//293 293//293 318//293
+f 295//294 294//294 319//294
+f 296//295 295//295 320//295
+f 296//296 320//296 297//296
+f 297//297 321//297 298//297
+f 298//298 322//298 299//298
+f 299//299 323//299 300//299
+f 300//1198 324//1198 301//1198
+f 301//301 325//301 302//301
+f 303//302 302//302 327//302
+f 304//303 303//303 328//303
+f 304//304 328//304 305//304
+f 305//305 329//305 306//305
+f 306//306 330//306 307//306
+f 308//307 307//307 332//307
+f 308//308 332//308 309//308
+f 309//309 333//309 310//309
+f 310//310 334//310 311//310
+f 312//311 311//311 336//311
+f 312//312 336//312 289//312
+f 313//313 337//313 314//313
+f 315//314 314//314 339//314
+f 316//315 315//315 340//315
+f 316//316 340//316 317//316
+f 317//317 341//317 318//317
+f 319//318 318//318 343//318
+f 319//319 343//319 320//319
+f 320//320 344//320 321//320
+f 322//321 321//321 346//321
+f 322//322 346//322 323//322
+f 324//323 323//323 348//323
+f 324//324 348//324 325//324
+f 326//325 325//325 350//325
+f 326//326 350//326 327//326
+f 328//327 327//327 352//327
+f 328//328 352//328 329//328
+f 329//329 353//329 330//329
+f 331//330 330//330 355//330
+f 331//331 355//331 332//331
+f 333//332 332//332 357//332
+f 334//333 333//333 358//333
+f 334//334 358//334 335//334
+f 335//335 359//335 336//335
+f 313//336 336//336 337//336
+f 338//337 337//337 362//337
+f 338//338 362//338 339//338
+f 340//339 339//339 364//339
+f 340//340 364//340 341//340
+f 341//341 365//341 342//341
+f 343//342 342//342 367//342
+f 343//343 367//343 344//343
+f 344//344 368//344 345//344
+f 346//345 345//345 370//345
+f 347//346 346//346 371//346
+f 348//347 347//347 372//347
+f 348//348 372//348 349//348
+f 349//349 373//349 350//349
+f 350//350 374//350 351//350
+f 351//351 375//351 352//351
+f 352//352 376//352 353//352
+f 353//353 377//353 354//353
+f 354//354 378//354 355//354
+f 355//355 379//355 356//355
+f 356//356 380//356 357//356
+f 357//357 381//357 358//357
+f 358//358 382//358 359//358
+f 360//359 359//359 384//359
+f 337//360 360//360 361//360
+f 361//361 385//361 362//361
+f 362//362 386//362 363//362
+f 364//1167 363//1167 388//1167
+f 364//364 388//364 365//364
+f 366//365 365//365 390//365
+f 366//366 390//366 367//366
+f 367//367 391//367 368//367
+f 368//368 392//368 369//368
+f 369//369 393//369 370//369
+f 370//370 394//370 371//370
+f 372//371 371//371 396//371
+f 372//372 396//372 373//372
+f 374//373 373//373 398//373
+f 374//374 398//374 375//374
+f 376//375 375//375 400//375
+f 376//376 400//376 377//376
+f 378//377 377//377 402//377
+f 379//378 378//378 403//378
+f 380//379 379//379 404//379
+f 380//380 404//380 381//380
+f 382//381 381//381 406//381
+f 383//1199 382//1199 407//1199
+f 384//383 383//383 408//383
+f 361//384 384//384 385//384
+f 386//385 385//385 410//385
+f 386//386 410//386 387//386
+f 388//387 387//387 412//387
+f 389//388 388//388 413//388
+f 389//389 413//389 390//389
+f 391//390 390//390 415//390
+f 392//391 391//391 416//391
+f 392//1200 416//1200 393//1200
+f 394//393 393//393 418//393
+f 394//394 418//394 395//394
+f 396//395 395//395 420//395
+f 396//396 420//396 397//396
+f 397//397 421//397 398//397
+f 398//398 422//398 399//398
+f 400//399 399//399 424//399
+f 400//400 424//400 401//400
+f 402//1201 401//1201 426//1201
+f 402//402 426//402 403//402
+f 403//403 427//403 404//403
+f 404//1202 428//1202 405//1202
+f 405//405 429//405 406//405
+f 406//406 430//406 407//406
+f 408//407 407//407 432//407
+f 408//408 432//408 385//408
+f 410//409 409//409 434//409
+f 410//410 434//410 411//410
+f 412//411 411//411 436//411
+f 412//412 436//412 413//412
+f 413//413 437//413 414//413
+f 414//414 438//414 415//414
+f 415//415 439//415 416//415
+f 416//416 440//416 417//416
+f 418//417 417//417 442//417
+f 418//418 442//418 419//418
+f 419//419 443//419 420//419
+f 420//420 444//420 421//420
+f 421//421 445//421 422//421
+f 423//422 422//422 447//422
+f 424//423 423//423 448//423
+f 424//424 448//424 425//424
+f 426//425 425//425 450//425
+f 427//426 426//426 451//426
+f 428//427 427//427 452//427
+f 429//428 428//428 453//428
+f 430//429 429//429 454//429
+f 430//430 454//430 431//430
+f 432//431 431//431 456//431
+f 432//432 456//432 409//432
+f 433//433 457//433 434//433
+f 434//434 458//434 435//434
+f 436//1168 435//1168 460//1168
+f 436//436 460//436 437//436
+f 438//437 437//437 462//437
+f 438//438 462//438 439//438
+f 440//439 439//439 464//439
+f 441//440 440//440 465//440
+f 442//441 441//441 466//441
+f 443//1203 442//1203 467//1203
+f 443//443 467//443 444//443
+f 445//444 444//444 469//444
+f 445//445 469//445 446//445
+f 446//446 470//446 447//446
+f 447//1204 471//1204 448//1204
+f 448//448 472//448 449//448
+f 449//449 473//449 450//449
+f 450//450 474//450 451//450
+f 452//451 451//451 476//451
+f 452//452 476//452 453//452
+f 454//453 453//453 478//453
+f 454//1169 478//1169 455//1169
+f 455//455 479//455 456//455
+f 456//456 480//456 433//456
+f 457//457 481//457 458//457
+f 458//458 482//458 459//458
+f 459//459 483//459 460//459
+f 460//460 484//460 461//460
+f 462//461 461//461 486//461
+f 462//462 486//462 463//462
+f 463//463 487//463 464//463
+f 465//464 464//464 489//464
+f 465//465 489//465 466//465
+f 466//466 490//466 467//466
+f 467//467 491//467 468//467
+f 469//468 468//468 493//468
+f 469//469 493//469 470//469
+f 470//470 494//470 471//470
+f 472//471 471//471 496//471
+f 473//472 472//472 497//472
+f 473//473 497//473 474//473
+f 474//474 498//474 475//474
+f 476//475 475//475 500//475
+f 476//476 500//476 477//476
+f 478//477 477//477 502//477
+f 478//478 502//478 479//478
+f 480//479 479//479 504//479
+f 480//480 504//480 457//480
+f 482//481 481//481 506//481
+f 483//482 482//482 507//482
+f 483//483 507//483 484//483
+f 484//484 508//484 485//484
+f 485//485 509//485 486//485
+f 486//486 510//486 487//486
+f 488//487 487//487 512//487
+f 488//488 512//488 489//488
+f 489//489 513//489 490//489
+f 490//1205 514//1205 491//1205
+f 491//491 515//491 492//491
+f 493//492 492//492 517//492
+f 493//493 517//493 494//493
+f 495//494 494//494 519//494
+f 495//495 519//495 496//495
+f 497//496 496//496 521//496
+f 497//497 521//497 498//497
+f 498//498 522//498 499//498
+f 500//499 499//499 524//499
+f 501//500 500//500 525//500
+f 502//501 501//501 526//501
+f 503//502 502//502 527//502
+f 504//503 503//503 528//503
+f 504//504 528//504 481//504
+f 506//505 505//505 530//505
+f 506//506 530//506 507//506
+f 507//507 531//507 508//507
+f 509//508 508//508 533//508
+f 509//509 533//509 510//509
+f 510//510 534//510 511//510
+f 512//511 511//511 536//511
+f 512//512 536//512 513//512
+f 513//513 537//513 514//513
+f 515//514 514//514 539//514
+f 515//515 539//515 516//515
+f 517//516 516//516 541//516
+f 517//517 541//517 518//517
+f 518//518 542//518 519//518
+f 519//519 543//519 520//519
+f 521//520 520//520 545//520
+f 522//521 521//521 546//521
+f 522//522 546//522 523//522
+f 523//523 547//523 524//523
+f 524//524 548//524 525//524
+f 525//525 549//525 526//525
+f 526//526 550//526 527//526
+f 528//527 527//527 552//527
+f 528//528 552//528 505//528
+f 530//529 529//529 554//529
+f 531//530 530//530 555//530
+f 532//531 531//531 556//531
+f 532//532 556//532 533//532
+f 533//533 557//533 534//533
+f 535//534 534//534 559//534
+f 536//535 535//535 560//535
+f 536//536 560//536 537//536
+f 537//537 561//537 538//537
+f 539//538 538//538 563//538
+f 540//539 539//539 564//539
+f 540//540 564//540 541//540
+f 541//541 565//541 542//541
+f 542//542 566//542 543//542
+f 543//543 567//543 544//543
+f 545//544 544//544 569//544
+f 545//545 569//545 546//545
+f 546//546 570//546 547//546
+f 548//547 547//547 572//547
+f 548//548 572//548 549//548
+f 550//549 549//549 574//549
+f 550//550 574//550 551//550
+f 551//551 575//551 552//551
+f 552//552 576//552 529//552
+f 553//553 577//553 554//553
+f 555//554 554//554 579//554
+f 555//555 579//555 556//555
+f 557//556 556//556 581//556
+f 557//557 581//557 558//557
+f 559//558 558//558 583//558
+f 560//559 559//559 584//559
+f 561//560 560//560 585//560
+f 562//561 561//561 586//561
+f 562//562 586//562 563//562
+f 564//563 563//563 588//563
+f 564//564 588//564 565//564
+f 566//565 565//565 590//565
+f 566//566 590//566 567//566
+f 568//567 567//567 592//567
+f 568//568 592//568 569//568
+f 569//569 593//569 570//569
+f 570//570 594//570 571//570
+f 571//571 595//571 572//571
+f 572//572 596//572 573//572
+f 573//573 597//573 574//573
+f 575//574 574//574 599//574
+f 575//575 599//575 576//575
+f 576//576 600//576 553//576
+f 578//1206 577//1206 602//1206
+f 579//578 578//578 603//578
+f 579//579 603//579 580//579
+f 580//580 604//580 581//580
+f 581//581 605//581 582//581
+f 583//582 582//582 607//582
+f 583//583 607//583 584//583
+f 584//584 608//584 585//584
+f 586//585 585//585 610//585
+f 586//586 610//586 587//586
+f 588//587 587//587 612//587
+f 588//588 612//588 589//588
+f 590//589 589//589 614//589
+f 590//590 614//590 591//590
+f 591//591 615//591 592//591
+f 592//592 616//592 593//592
+f 594//593 593//593 618//593
+f 595//594 594//594 619//594
+f 595//595 619//595 596//595
+f 597//596 596//596 621//596
+f 598//597 597//597 622//597
+f 599//598 598//598 623//598
+f 599//599 623//599 600//599
+f 600//1207 624//1207 577//1207
+f 602//601 601//601 626//601
+f 602//602 626//602 603//602
+f 604//603 603//603 628//603
+f 605//604 604//604 629//604
+f 605//605 629//605 606//605
+f 607//606 606//606 631//606
+f 608//607 607//607 632//607
+f 608//608 632//608 609//608
+f 609//609 633//609 610//609
+f 610//610 634//610 611//610
+f 611//611 635//611 612//611
+f 612//612 636//612 613//612
+f 613//613 637//613 614//613
+f 615//614 614//614 639//614
+f 616//615 615//615 640//615
+f 616//616 640//616 617//616
+f 617//617 641//617 618//617
+f 618//618 642//618 619//618
+f 619//619 643//619 620//619
+f 621//620 620//620 645//620
+f 621//621 645//621 622//621
+f 622//622 646//622 623//622
+f 624//623 623//623 648//623
+f 624//624 648//624 601//624
+f 625//625 649//625 626//625
+f 626//626 650//626 627//626
+f 627//627 651//627 628//627
+f 629//628 628//628 653//628
+f 629//629 653//629 630//629
+f 630//1208 654//1208 631//1208
+f 631//1172 655//1172 632//1172
+f 632//632 656//632 633//632
+f 634//633 633//633 658//633
+f 634//634 658//634 635//634
+f 636//635 635//635 660//635
+f 637//636 636//636 661//636
+f 637//637 661//637 638//637
+f 638//638 662//638 639//638
+f 639//639 663//639 640//639
+f 640//640 664//640 641//640
+f 641//641 665//641 642//641
+f 642//642 666//642 643//642
+f 644//643 643//643 668//643
+f 645//644 644//644 669//644
+f 645//645 669//645 646//645
+f 647//646 646//646 671//646
+f 648//647 647//647 672//647
+f 625//648 648//648 649//648
+f 650//649 649//649 674//649
+f 651//650 650//650 675//650
+f 651//651 675//651 652//651
+f 653//652 652//652 677//652
+f 654//653 653//653 678//653
+f 655//654 654//654 679//654
+f 656//655 655//655 680//655
+f 656//656 680//656 657//656
+f 658//657 657//657 682//657
+f 658//658 682//658 659//658
+f 660//659 659//659 684//659
+f 660//660 684//660 661//660
+f 661//661 685//661 662//661
+f 662//662 686//662 663//662
+f 664//663 663//663 688//663
+f 664//664 688//664 665//664
+f 665//665 689//665 666//665
+f 666//666 690//666 667//666
+f 667//667 691//667 668//667
+f 668//668 692//668 669//668
+f 670//669 669//669 694//669
+f 670//670 694//670 671//670
+f 671//671 695//671 672//671
+f 672//672 696//672 649//672
+f 673//673 697//673 674//673
+f 675//674 674//674 699//674
+f 675//675 699//675 676//675
+f 676//676 700//676 677//676
+f 677//677 701//677 678//677
+f 678//678 702//678 679//678
+f 680//679 679//679 704//679
+f 680//680 704//680 681//680
+f 681//681 705//681 682//681
+f 682//682 706//682 683//682
+f 683//683 707//683 684//683
+f 685//684 684//684 709//684
+f 685//685 709//685 686//685
+f 687//686 686//686 711//686
+f 688//687 687//687 712//687
+f 689//688 688//688 713//688
+f 690//689 689//689 714//689
+f 690//690 714//690 691//690
+f 692//691 691//691 716//691
+f 693//692 692//692 717//692
+f 694//693 693//693 718//693
+f 695//694 694//694 719//694
+f 695//695 719//695 696//695
+f 673//696 696//696 697//696
+f 698//697 697//697 722//697
+f 699//698 698//698 723//698
+f 699//1174 723//1174 700//1174
+f 701//700 700//700 725//700
+f 702//701 701//701 726//701
+f 702//702 726//702 703//702
+f 703//703 727//703 704//703
+f 704//704 728//704 705//704
+f 705//705 729//705 706//705
+f 707//706 706//706 731//706
+f 707//707 731//707 708//707
+f 709//708 708//708 733//708
+f 709//709 733//709 710//709
+f 710//710 734//710 711//710
+f 711//711 735//711 712//711
+f 713//712 712//712 737//712
+f 713//713 737//713 714//713
+f 715//714 714//714 739//714
+f 715//715 739//715 716//715
+f 717//716 716//716 741//716
+f 717//717 741//717 718//717
+f 719//1175 718//1175 743//1175
+f 719//719 743//719 720//719
+f 720//720 744//720 697//720
+f 722//721 721//721 746//721
+f 723//722 722//722 747//722
+f 723//723 747//723 724//723
+f 724//724 748//724 725//724
+f 725//725 749//725 726//725
+f 727//726 726//726 751//726
+f 727//727 751//727 728//727
+f 729//728 728//728 753//728
+f 729//729 753//729 730//729
+f 731//730 730//730 755//730
+f 731//731 755//731 732//731
+f 732//732 756//732 733//732
+f 734//733 733//733 758//733
+f 735//734 734//734 759//734
+f 735//735 759//735 736//735
+f 736//736 760//736 737//736
+f 737//737 761//737 738//737
+f 739//738 738//738 763//738
+f 739//739 763//739 740//739
+f 741//740 740//740 765//740
+f 742//741 741//741 766//741
+f 743//742 742//742 767//742
+f 743//743 767//743 744//743
+f 744//744 768//744 721//744
+f 746//745 745//745 770//745
+f 747//746 746//746 771//746
+f 748//747 747//747 772//747
+f 748//748 772//748 749//748
+f 750//749 749//749 774//749
+f 750//750 774//750 751//750
+f 752//751 751//751 776//751
+f 753//752 752//752 777//752
+f 754//753 753//753 778//753
+f 755//754 754//754 779//754
+f 755//755 779//755 756//755
+f 756//756 780//756 757//756
+f 758//757 757//757 782//757
+f 759//758 758//758 783//758
+f 759//759 783//759 760//759
+f 760//760 784//760 761//760
+f 761//761 785//761 762//761
+f 762//762 786//762 763//762
+f 763//763 787//763 764//763
+f 764//764 788//764 765//764
+f 766//765 765//765 790//765
+f 766//766 790//766 767//766
+f 767//767 791//767 768//767
+f 768//768 792//768 745//768
+f 770//769 769//769 794//769
+f 770//770 794//770 771//770
+f 771//771 795//771 772//771
+f 772//772 796//772 773//772
+f 773//773 797//773 774//773
+f 774//774 798//774 775//774
+f 775//775 799//775 776//775
+f 776//776 800//776 777//776
+f 777//777 801//777 778//777
+f 778//1179 802//1179 779//1179
+f 779//779 803//779 780//779
+f 780//780 804//780 781//780
+f 781//781 805//781 782//781
+f 783//782 782//782 807//782
+f 784//1180 783//1180 808//1180
+f 784//784 808//784 785//784
+f 786//785 785//785 810//785
+f 787//786 786//786 811//786
+f 788//787 787//787 812//787
+f 788//788 812//788 789//788
+f 790//789 789//789 814//789
+f 790//1209 814//1209 791//1209
+f 792//791 791//791 816//791
+f 792//792 816//792 769//792
+f 794//793 793//793 818//793
+f 794//794 818//794 795//794
+f 796//795 795//795 820//795
+f 797//796 796//796 821//796
+f 798//797 797//797 822//797
+f 799//798 798//798 823//798
+f 800//799 799//799 824//799
+f 801//800 800//800 825//800
+f 801//801 825//801 802//801
+f 803//802 802//802 827//802
+f 803//803 827//803 804//803
+f 805//804 804//804 829//804
+f 805//805 829//805 806//805
+f 806//806 830//806 807//806
+f 807//807 831//807 808//807
+f 808//808 832//808 809//808
+f 809//809 833//809 810//809
+f 810//810 834//810 811//810
+f 811//811 835//811 812//811
+f 812//812 836//812 813//812
+f 813//813 837//813 814//813
+f 814//814 838//814 815//814
+f 816//815 815//815 840//815
+f 816//816 840//816 793//816
+f 817//817 841//817 818//817
+f 818//818 842//818 819//818
+f 820//819 819//819 844//819
+f 820//820 844//820 821//820
+f 822//821 821//821 846//821
+f 822//822 846//822 823//822
+f 823//823 847//823 824//823
+f 825//824 824//824 849//824
+f 825//825 849//825 826//825
+f 826//826 850//826 827//826
+f 827//827 851//827 828//827
+f 829//828 828//828 853//828
+f 829//829 853//829 830//829
+f 831//830 830//830 855//830
+f 832//831 831//831 856//831
+f 833//832 832//832 857//832
+f 833//833 857//833 834//833
+f 835//834 834//834 859//834
+f 835//835 859//835 836//835
+f 836//836 860//836 837//836
+f 837//837 861//837 838//837
+f 838//838 862//838 839//838
+f 839//839 863//839 840//839
+f 817//840 840//840 841//840
+f 841//841 865//841 842//841
+f 843//842 842//842 867//842
+f 843//843 867//843 844//843
+f 844//844 868//844 845//844
+f 846//845 845//845 870//845
+f 847//846 846//846 871//846
+f 847//847 871//847 848//847
+f 849//848 848//848 873//848
+f 850//849 849//849 874//849
+f 850//850 874//850 851//850
+f 851//851 875//851 852//851
+f 853//852 852//852 877//852
+f 853//853 877//853 854//853
+f 855//854 854//854 879//854
+f 856//855 855//855 880//855
+f 857//856 856//856 881//856
+f 857//857 881//857 858//857
+f 859//858 858//858 883//858
+f 860//859 859//859 884//859
+f 860//860 884//860 861//860
+f 861//861 885//861 862//861
+f 863//862 862//862 887//862
+f 863//863 887//863 864//863
+f 841//864 864//864 865//864
+f 865//865 889//865 866//865
+f 867//866 866//866 891//866
+f 867//867 891//867 868//867
+f 869//868 868//868 893//868
+f 869//869 893//869 870//869
+f 870//870 894//870 871//870
+f 871//871 895//871 872//871
+f 872//872 896//872 873//872
+f 874//873 873//873 898//873
+f 875//874 874//874 899//874
+f 876//875 875//875 900//875
+f 877//1210 876//1210 901//1210
+f 877//1211 901//1211 878//1211
+f 879//878 878//878 903//878
+f 879//879 903//879 880//879
+f 881//880 880//880 905//880
+f 881//881 905//881 882//881
+f 883//882 882//882 907//882
+f 884//883 883//883 908//883
+f 884//884 908//884 885//884
+f 885//885 909//885 886//885
+f 887//886 886//886 911//886
+f 887//887 911//887 888//887
+f 865//1212 888//1212 889//1212
+f 889//889 913//889 890//889
+f 890//890 914//890 891//890
+f 891//891 915//891 892//891
+f 893//892 892//892 917//892
+f 893//893 917//893 894//893
+f 894//894 918//894 895//894
+f 895//895 919//895 896//895
+f 897//896 896//896 921//896
+f 897//897 921//897 898//897
+f 899//898 898//898 923//898
+f 899//1185 923//1185 900//1185
+f 900//900 924//900 901//900
+f 901//901 925//901 902//901
+f 903//902 902//902 927//902
+f 903//903 927//903 904//903
+f 905//904 904//904 929//904
+f 905//905 929//905 906//905
+f 906//906 930//906 907//906
+f 908//907 907//907 932//907
+f 909//908 908//908 933//908
+f 909//909 933//909 910//909
+f 911//910 910//910 935//910
+f 911//911 935//911 912//911
+f 889//912 912//912 913//912
+f 914//913 913//913 938//913
+f 915//914 914//914 939//914
+f 915//915 939//915 916//915
+f 916//916 940//916 917//916
+f 918//917 917//917 942//917
+f 918//918 942//918 919//918
+f 919//919 943//919 920//919
+f 920//920 944//920 921//920
+f 921//921 945//921 922//921
+f 922//922 946//922 923//922
+f 923//923 947//923 924//923
+f 925//924 924//924 949//924
+f 926//925 925//925 950//925
+f 926//926 950//926 927//926
+f 928//927 927//927 952//927
+f 928//928 952//928 929//928
+f 930//929 929//929 954//929
+f 930//930 954//930 931//930
+f 932//931 931//931 956//931
+f 932//932 956//932 933//932
+f 933//933 957//933 934//933
+f 935//934 934//934 959//934
+f 935//935 959//935 936//935
+f 936//936 960//936 913//936
+f 938//937 937//937 962//937
+f 939//938 938//938 963//938
+f 940//1187 939//1187 964//1187
+f 941//940 940//940 965//940
+f 942//941 941//941 966//941
+f 943//942 942//942 967//942
+f 944//943 943//943 968//943
+f 945//944 944//944 969//944
+f 946//945 945//945 970//945
+f 947//1186 946//1186 971//1186
+f 948//947 947//947 972//947
+f 948//948 972//948 949//948
+f 950//949 949//949 974//949
+f 950//950 974//950 951//950
+f 951//1188 975//1188 952//1188
+f 952//952 976//952 953//952
+f 953//953 977//953 954//953
+f 954//954 978//954 955//954
+f 955//955 979//955 956//955
+f 956//956 980//956 957//956
+f 957//957 981//957 958//957
+f 959//958 958//958 983//958
+f 959//959 983//959 960//959
+f 960//960 984//960 937//960
+f 962//961 961//961 986//961
+f 963//962 962//962 987//962
+f 964//963 963//963 988//963
+f 964//964 988//964 965//964
+f 965//965 989//965 966//965
+f 967//966 966//966 991//966
+f 967//967 991//967 968//967
+f 968//968 992//968 969//968
+f 969//969 993//969 970//969
+f 970//970 994//970 971//970
+f 972//971 971//971 996//971
+f 972//972 996//972 973//972
+f 974//973 973//973 998//973
+f 974//974 998//974 975//974
+f 975//975 999//975 976//975
+f 976//976 1000//976 977//976
+f 978//977 977//977 1002//977
+f 978//978 1002//978 979//978
+f 979//979 1003//979 980//979
+f 981//980 980//980 1005//980
+f 981//981 1005//981 982//981
+f 982//982 1006//982 983//982
+f 983//983 1007//983 984//983
+f 984//984 1008//984 961//984
+f 985//985 1009//985 986//985
+f 986//986 1010//986 987//986
+f 987//987 1011//987 988//987
+f 988//988 1012//988 989//988
+f 989//989 1013//989 990//989
+f 990//990 1014//990 991//990
+f 991//991 1015//991 992//991
+f 992//992 1016//992 993//992
+f 993//993 1017//993 994//993
+f 994//994 1018//994 995//994
+f 995//995 1019//995 996//995
+f 996//996 1020//996 997//996
+f 997//997 1021//997 998//997
+f 999//998 998//998 1023//998
+f 999//999 1023//999 1000//999
+f 1000//1000 1024//1000 1001//1000
+f 1002//1001 1001//1001 1026//1001
+f 1003//1002 1002//1002 1027//1002
+f 1004//1003 1003//1003 1028//1003
+f 1005//1004 1004//1004 1029//1004
+f 1005//1005 1029//1005 1006//1005
+f 1007//1006 1006//1006 1031//1006
+f 1008//1007 1007//1007 1032//1007
+f 1008//1008 1032//1008 985//1008
+f 1010//1009 1009//1009 1034//1009
+f 1011//1010 1010//1010 1035//1010
+f 1012//1191 1011//1191 1036//1191
+f 1012//1012 1036//1012 1013//1012
+f 1014//1013 1013//1013 1038//1013
+f 1015//1014 1014//1014 1039//1014
+f 1016//1015 1015//1015 1040//1015
+f 1017//1016 1016//1016 1041//1016
+f 1018//1017 1017//1017 1042//1017
+f 1019//1018 1018//1018 1043//1018
+f 1019//1019 1043//1019 1020//1019
+f 1021//1020 1020//1020 1045//1020
+f 1021//1021 1045//1021 1022//1021
+f 1022//1022 1046//1022 1023//1022
+f 1023//1023 1047//1023 1024//1023
+f 1024//1024 1048//1024 1025//1024
+f 1025//1025 1049//1025 1026//1025
+f 1026//1026 1050//1026 1027//1026
+f 1027//1027 1051//1027 1028//1027
+f 1028//1028 1052//1028 1029//1028
+f 1030//1029 1029//1029 1054//1029
+f 1030//1192 1054//1192 1031//1192
+f 1031//1031 1055//1031 1032//1031
+f 1032//1032 1056//1032 1009//1032
+f 1034//1033 1033//1033 1058//1033
+f 1034//1034 1058//1034 1035//1034
+f 1035//1035 1059//1035 1036//1035
+f 1037//1036 1036//1036 1061//1036
+f 1038//1037 1037//1037 1062//1037
+f 1038//1038 1062//1038 1039//1038
+f 1039//1039 1063//1039 1040//1039
+f 1041//1040 1040//1040 1065//1040
+f 1042//1041 1041//1041 1066//1041
+f 1043//1042 1042//1042 1067//1042
+f 1043//1043 1067//1043 1044//1043
+f 1044//1044 1068//1044 1045//1044
+f 1045//1045 1069//1045 1046//1045
+f 1047//1046 1046//1046 1071//1046
+f 1047//1047 1071//1047 1048//1047
+f 1048//1048 1072//1048 1049//1048
+f 1049//1049 1073//1049 1050//1049
+f 1051//1050 1050//1050 1075//1050
+f 1052//1051 1051//1051 1076//1051
+f 1052//1052 1076//1052 1053//1052
+f 1053//1053 1077//1053 1054//1053
+f 1054//1054 1078//1054 1055//1054
+f 1056//1055 1055//1055 1080//1055
+f 1056//1056 1080//1056 1033//1056
+f 1057//1057 1081//1057 1058//1057
+f 1059//1058 1058//1058 1083//1058
+f 1059//1059 1083//1059 1060//1059
+f 1060//1060 1084//1060 1061//1060
+f 1061//1061 1085//1061 1062//1061
+f 1062//1062 1086//1062 1063//1062
+f 1063//1063 1087//1063 1064//1063
+f 1064//1064 1088//1064 1065//1064
+f 1065//1065 1089//1065 1066//1065
+f 1067//1066 1066//1066 1091//1066
+f 1067//1067 1091//1067 1068//1067
+f 1068//1068 1092//1068 1069//1068
+f 1069//1069 1093//1069 1070//1069
+f 1071//1070 1070//1070 1095//1070
+f 1071//1071 1095//1071 1072//1071
+f 1073//1072 1072//1072 1097//1072
+f 1074//1073 1073//1073 1098//1073
+f 1075//1074 1074//1074 1099//1074
+f 1076//1075 1075//1075 1100//1075
+f 1077//1076 1076//1076 1101//1076
+f 1078//1077 1077//1077 1102//1077
+f 1079//1078 1078//1078 1103//1078
+f 1079//1079 1103//1079 1080//1079
+f 1057//1080 1080//1080 1081//1080
+f 1081//1081 1105//1081 1082//1081
+f 1082//1082 1106//1082 1083//1082
+f 1084//1083 1083//1083 1108//1083
+f 1085//1084 1084//1084 1109//1084
+f 1086//1085 1085//1085 1110//1085
+f 1087//1086 1086//1086 1111//1086
+f 1087//1087 1111//1087 1088//1087
+f 1089//1088 1088//1088 1113//1088
+f 1090//1089 1089//1089 1114//1089
+f 1091//1090 1090//1090 1115//1090
+f 1091//1091 1115//1091 1092//1091
+f 1092//1092 1116//1092 1093//1092
+f 1093//1093 1117//1093 1094//1093
+f 1094//1094 1118//1094 1095//1094
+f 1095//1095 1119//1095 1096//1095
+f 1096//1096 1120//1096 1097//1096
+f 1097//1097 1121//1097 1098//1097
+f 1098//1213 1122//1213 1099//1213
+f 1099//1214 1123//1214 1100//1214
+f 1100//1100 1124//1100 1101//1100
+f 1101//1101 1125//1101 1102//1101
+f 1102//1102 1126//1102 1103//1102
+f 1103//1103 1127//1103 1104//1103
+f 1081//1104 1104//1104 1105//1104
+f 1106//1105 1105//1105 1130//1105
+f 1106//1106 1130//1106 1107//1106
+f 1107//1107 1131//1107 1108//1107
+f 1108//1108 1132//1108 1109//1108
+f 1109//1109 1133//1109 1110//1109
+f 1110//1110 1134//1110 1111//1110
+f 1111//1111 1135//1111 1112//1111
+f 1112//1112 1136//1112 1113//1112
+f 1113//1113 1137//1113 1114//1113
+f 1114//1114 1138//1114 1115//1114
+f 1115//1115 1139//1115 1116//1115
+f 1116//1116 1140//1116 1117//1116
+f 1117//1117 1141//1117 1118//1117
+f 1119//1118 1118//1118 1143//1118
+f 1120//1119 1119//1119 1144//1119
+f 1121//1120 1120//1120 1145//1120
+f 1122//1121 1121//1121 1146//1121
+f 1123//1122 1122//1122 1147//1122
+f 1124//1123 1123//1123 1148//1123
+f 1124//1124 1148//1124 1125//1124
+f 1126//1125 1125//1125 1150//1125
+f 1127//1126 1126//1126 1151//1126
+f 1127//1127 1151//1127 1128//1127
+f 1128//1128 1152//1128 1105//1128
+f 1129//1129 1153//1129 1130//1129
+f 1131//1130 1130//1130 1155//1130
+f 1131//1131 1155//1131 1132//1131
+f 1132//1132 1156//1132 1133//1132
+f 1133//1133 1157//1133 1134//1133
+f 1134//1134 1158//1134 1135//1134
+f 1136//1135 1135//1135 1160//1135
+f 1136//1136 1160//1136 1137//1136
+f 1137//1137 1161//1137 1138//1137
+f 1138//1138 1162//1138 1139//1138
+f 1140//1139 1139//1139 1164//1139
+f 1140//1140 1164//1140 1141//1140
+f 1141//1141 1165//1141 1142//1141
+f 1142//1142 1166//1142 1143//1142
+f 1144//1143 1143//1143 1168//1143
+f 1144//1144 1168//1144 1145//1144
+f 1146//1145 1145//1145 1170//1145
+f 1146//1146 1170//1146 1147//1146
+f 1148//1147 1147//1147 1172//1147
+f 1149//1148 1148//1148 1173//1148
+f 1150//1149 1149//1149 1174//1149
+f 1151//1150 1150//1150 1175//1150
+f 1151//1151 1175//1151 1152//1151
+f 1152//1152 1176//1152 1129//1152
+f 1154//12 1153//12 1178//12
+f 1155//11 1154//11 1179//11
+f 1156//10 1155//10 1180//10
+f 1156//9 1180//9 1157//9
+f 1157//8 1181//8 1158//8
+f 1158//7 1182//7 1159//7
+f 1159//6 1183//6 1160//6
+f 1161//5 1160//5 1185//5
+f 1162//4 1161//4 1186//4
+f 1162//3 1186//3 1163//3
+f 1163//2 1187//2 1164//2
+f 1164//1 1188//1 1165//1
+f 1166//24 1165//24 1190//24
+f 1167//23 1166//23 1191//23
+f 1167//22 1191//22 1168//22
+f 1168//21 1192//21 1169//21
+f 1169//20 1193//20 1170//20
+f 1171//19 1170//19 1195//19
+f 1172//18 1171//18 1196//18
+f 1173//17 1172//17 1197//17
+f 1173//16 1197//16 1174//16
+f 1174//15 1198//15 1175//15
+f 1175//14 1199//14 1176//14
+f 1176//13 1200//13 1153//13
+f 1177//36 1201//36 1178//36
+f 1178//35 1202//35 1179//35
+f 1180//34 1179//34 1204//34
+f 1181//33 1180//33 1205//33
+f 1182//32 1181//32 1206//32
+f 1183//31 1182//31 1207//31
+f 1183//30 1207//30 1184//30
+f 1185//29 1184//29 1209//29
+f 1186//28 1185//28 1210//28
+f 1187//27 1186//27 1211//27
+f 1188//26 1187//26 1212//26
+f 1189//25 1188//25 1213//25
+f 1189//48 1213//48 1190//48
+f 1190//47 1214//47 1191//47
+f 1191//46 1215//46 1192//46
+f 1192//45 1216//45 1193//45
+f 1193//44 1217//44 1194//44
+f 1194//43 1218//43 1195//43
+f 1195//42 1219//42 1196//42
+f 1196//41 1220//41 1197//41
+f 1197//40 1221//40 1198//40
+f 1198//39 1222//39 1199//39
+f 1199//38 1223//38 1200//38
+f 1200//37 1224//37 1177//37
+f 1201//60 1225//60 1202//60
+f 1202//59 1226//59 1203//59
+f 1203//58 1227//58 1204//58
+f 1204//57 1228//57 1205//57
+f 1205//56 1229//56 1206//56
+f 1206//55 1230//55 1207//55
+f 1207//54 1231//54 1208//54
+f 1208//53 1232//53 1209//53
+f 1209//52 1233//52 1210//52
+f 1210//51 1234//51 1211//51
+f 1211//50 1235//50 1212//50
+f 1212//49 1236//49 1213//49
+f 1213//72 1237//72 1214//72
+f 1214//71 1238//71 1215//71
+f 1215//70 1239//70 1216//70
+f 1217//69 1216//69 1241//69
+f 1218//68 1217//68 1242//68
+f 1218//67 1242//67 1219//67
+f 1220//66 1219//66 1244//66
+f 1221//65 1220//65 1245//65
+f 1222//64 1221//64 1246//64
+f 1223//63 1222//63 1247//63
+f 1223//62 1247//62 1224//62
+f 1224//61 1248//61 1201//61
+f 1226//84 1225//84 1250//84
+f 1226//83 1250//83 1227//83
+f 1228//82 1227//82 1252//82
+f 1229//81 1228//81 1253//81
+f 1230//80 1229//80 1254//80
+f 1231//79 1230//79 1255//79
+f 1232//78 1231//78 1256//78
+f 1233//77 1232//77 1257//77
+f 1234//76 1233//76 1258//76
+f 1234//75 1258//75 1235//75
+f 1236//74 1235//74 1260//74
+f 1236//73 1260//73 1237//73
+f 1237//96 1261//96 1238//96
+f 1238//95 1262//95 1239//95
+f 1240//94 1239//94 1264//94
+f 1240//93 1264//93 1241//93
+f 1241//92 1265//92 1242//92
+f 1242//91 1266//91 1243//91
+f 1243//90 1267//90 1244//90
+f 1244//89 1268//89 1245//89
+f 1245//88 1269//88 1246//88
+f 1246//87 1270//87 1247//87
+f 1248//86 1247//86 1272//86
+f 1248//85 1272//85 1225//85
+f 1249//108 1273//108 1250//108
+f 1251//107 1250//107 1275//107
+f 1252//106 1251//106 1276//106
+f 1252//105 1276//105 1253//105
+f 1254//104 1253//104 1278//104
+f 1255//103 1254//103 1279//103
+f 1256//102 1255//102 1280//102
+f 1256//101 1280//101 1257//101
+f 1257//100 1281//100 1258//100
+f 1258//99 1282//99 1259//99
+f 1260//98 1259//98 1284//98
+f 1260//97 1284//97 1261//97
+f 1261//120 1285//120 1262//120
+f 1262//119 1286//119 1263//119
+f 1264//118 1263//118 1288//118
+f 1265//117 1264//117 1289//117
+f 1266//116 1265//116 1290//116
+f 1266//115 1290//115 1267//115
+f 1267//114 1291//114 1268//114
+f 1268//113 1292//113 1269//113
+f 1270//112 1269//112 1294//112
+f 1270//111 1294//111 1271//111
+f 1271//110 1295//110 1272//110
+f 1249//109 1272//109 1273//109
+f 1273//132 1297//132 1274//132
+f 1275//131 1274//131 1299//131
+f 1275//1215 1299//1215 1276//1215
+f 1276//129 1300//129 1277//129
+f 1277//128 1301//128 1278//128
+f 1278//127 1302//127 1279//127
+f 1279//126 1303//126 1280//126
+f 1280//125 1304//125 1281//125
+f 1281//124 1305//124 1282//124
+f 1282//123 1306//123 1283//123
+f 1283//122 1307//122 1284//122
+f 1284//121 1308//121 1285//121
+f 1286//144 1285//144 1310//144
+f 1286//143 1310//143 1287//143
+f 1288//142 1287//142 1312//142
+f 1289//141 1288//141 1313//141
+f 1290//140 1289//140 1314//140
+f 1291//139 1290//139 1315//139
+f 1292//138 1291//138 1316//138
+f 1293//137 1292//137 1317//137
+f 1293//136 1317//136 1294//136
+f 1295//1216 1294//1216 1319//1216
+f 1295//134 1319//134 1296//134
+f 1273//133 1296//133 1297//133
+f 1298//156 1297//156 1322//156
+f 1299//155 1298//155 1323//155
+f 1299//154 1323//154 1300//154
+f 1301//153 1300//153 1325//153
+f 1301//152 1325//152 1302//152
+f 1303//151 1302//151 1327//151
+f 1304//150 1303//150 1328//150
+f 1305//149 1304//149 1329//149
+f 1306//148 1305//148 1330//148
+f 1307//147 1306//147 1331//147
+f 1308//146 1307//146 1332//146
+f 1309//145 1308//145 1333//145
+f 1309//168 1333//168 1310//168
+f 1310//167 1334//167 1311//167
+f 1311//166 1335//166 1312//166
+f 1312//165 1336//165 1313//165
+f 1313//164 1337//164 1314//164
+f 1315//163 1314//163 1339//163
+f 1315//162 1339//162 1316//162
+f 1317//161 1316//161 1341//161
+f 1317//160 1341//160 1318//160
+f 1318//159 1342//159 1319//159
+f 1319//158 1343//158 1320//158
+f 1320//157 1344//157 1297//157
+f 1321//180 1345//180 1322//180
+f 1322//179 1346//179 1323//179
+f 1323//178 1347//178 1324//178
+f 1324//177 1348//177 1325//177
+f 1326//176 1325//176 1350//176
+f 1327//175 1326//175 1351//175
+f 1328//174 1327//174 1352//174
+f 1329//173 1328//173 1353//173
+f 1329//172 1353//172 1330//172
+f 1331//171 1330//171 1355//171
+f 1331//1155 1355//1155 1332//1155
+f 1332//169 1356//169 1333//169
+f 1333//192 1357//192 1334//192
+f 1334//191 1358//191 1335//191
+f 1335//190 1359//190 1336//190
+f 1336//189 1360//189 1337//189
+f 1337//188 1361//188 1338//188
+f 1338//187 1362//187 1339//187
+f 1339//186 1363//186 1340//186
+f 1340//185 1364//185 1341//185
+f 1341//184 1365//184 1342//184
+f 1343//183 1342//183 1367//183
+f 1344//182 1343//182 1368//182
+f 1344//181 1368//181 1321//181
+f 1345//204 1369//204 1346//204
+f 1346//203 1370//203 1347//203
+f 1347//1217 1371//1217 1348//1217
+f 1348//201 1372//201 1349//201
+f 1349//200 1373//200 1350//200
+f 1351//199 1350//199 1375//199
+f 1351//198 1375//198 1352//198
+f 1352//197 1376//197 1353//197
+f 1353//196 1377//196 1354//196
+f 1354//195 1378//195 1355//195
+f 1355//194 1379//194 1356//194
+f 1357//193 1356//193 1381//193
+f 1357//216 1381//216 1358//216
+f 1359//215 1358//215 1383//215
+f 1360//214 1359//214 1384//214
+f 1361//213 1360//213 1385//213
+f 1362//212 1361//212 1386//212
+f 1363//211 1362//211 1387//211
+f 1363//210 1387//210 1364//210
+f 1365//209 1364//209 1389//209
+f 1366//208 1365//208 1390//208
+f 1367//1218 1366//1218 1391//1218
+f 1368//206 1367//206 1392//206
+f 1368//205 1392//205 1345//205
+f 1369//228 1393//228 1370//228
+f 1370//227 1394//227 1371//227
+f 1372//226 1371//226 1396//226
+f 1372//225 1396//225 1373//225
+f 1373//224 1397//224 1374//224
+f 1375//223 1374//223 1399//223
+f 1375//222 1399//222 1376//222
+f 1377//221 1376//221 1401//221
+f 1377//220 1401//220 1378//220
+f 1379//219 1378//219 1403//219
+f 1379//218 1403//218 1380//218
+f 1380//217 1404//217 1381//217
+f 1381//240 1405//240 1382//240
+f 1382//239 1406//239 1383//239
+f 1383//238 1407//238 1384//238
+f 1385//237 1384//237 1409//237
+f 1385//236 1409//236 1386//236
+f 1386//235 1410//235 1387//235
+f 1387//234 1411//234 1388//234
+f 1389//233 1388//233 1413//233
+f 1389//232 1413//232 1390//232
+f 1390//231 1414//231 1391//231
+f 1392//230 1391//230 1416//230
+f 1369//229 1392//229 1393//229
+f 1393//252 1417//252 1394//252
+f 1394//251 1418//251 1395//251
+f 1396//250 1395//250 1420//250
+f 1396//249 1420//249 1397//249
+f 1398//248 1397//248 1422//248
+f 1399//247 1398//247 1423//247
+f 1399//246 1423//246 1400//246
+f 1401//245 1400//245 1425//245
+f 1402//244 1401//244 1426//244
+f 1402//243 1426//243 1403//243
+f 1404//242 1403//242 1428//242
+f 1405//241 1404//241 1429//241
+f 1405//264 1429//264 1406//264
+f 1406//263 1430//263 1407//263
+f 1408//262 1407//262 1432//262
+f 1408//261 1432//261 1409//261
+f 1409//260 1433//260 1410//260
+f 1411//259 1410//259 1435//259
+f 1411//258 1435//258 1412//258
+f 1412//257 1436//257 1413//257
+f 1414//256 1413//256 1438//256
+f 1414//255 1438//255 1415//255
+f 1415//254 1439//254 1416//254
+f 1416//253 1440//253 1393//253
+f 1418//1158 1417//1158 1442//1158
+f 1418//275 1442//275 1419//275
+f 1420//274 1419//274 1444//274
+f 1420//273 1444//273 1421//273
+f 1421//272 1445//272 1422//272
+f 1423//271 1422//271 1447//271
+f 1424//270 1423//270 1448//270
+f 1424//269 1448//269 1425//269
+f 1426//268 1425//268 1450//268
+f 1426//267 1450//267 1427//267
+f 1428//266 1427//266 1452//266
+f 1428//265 1452//265 1429//265
+f 1430//288 1429//288 1454//288
+f 1431//287 1430//287 1455//287
+f 1432//286 1431//286 1456//286
+f 1433//285 1432//285 1457//285
+f 1433//284 1457//284 1434//284
+f 1434//283 1458//283 1435//283
+f 1435//282 1459//282 1436//282
+f 1436//281 1460//281 1437//281
+f 1438//280 1437//280 1462//280
+f 1438//279 1462//279 1439//279
+f 1440//278 1439//278 1464//278
+f 1440//277 1464//277 1417//277
+f 1442//300 1441//300 1466//300
+f 1442//299 1466//299 1443//299
+f 1443//298 1467//298 1444//298
+f 1444//297 1468//297 1445//297
+f 1445//296 1469//296 1446//296
+f 1446//295 1470//295 1447//295
+f 1447//294 1471//294 1448//294
+f 1448//293 1472//293 1449//293
+f 1449//292 1473//292 1450//292
+f 1450//291 1474//291 1451//291
+f 1452//290 1451//290 1476//290
+f 1453//289 1452//289 1477//289
+f 1453//312 1477//312 1454//312
+f 1454//311 1478//311 1455//311
+f 1455//310 1479//310 1456//310
+f 1457//309 1456//309 1481//309
+f 1457//308 1481//308 1458//308
+f 1458//307 1482//307 1459//307
+f 1459//306 1483//306 1460//306
+f 1461//305 1460//305 1485//305
+f 1462//304 1461//304 1486//304
+f 1463//303 1462//303 1487//303
+f 1464//302 1463//302 1488//302
+f 1464//301 1488//301 1441//301
+f 1466//324 1465//324 1490//324
+f 1466//1162 1490//1162 1467//1162
+f 1468//322 1467//322 1492//322
+f 1469//321 1468//321 1493//321
+f 1470//320 1469//320 1494//320
+f 1471//319 1470//319 1495//319
+f 1472//318 1471//318 1496//318
+f 1473//317 1472//317 1497//317
+f 1474//316 1473//316 1498//316
+f 1475//315 1474//315 1499//315
+f 1476//314 1475//314 1500//314
+f 1476//313 1500//313 1477//313
+f 1477//336 1501//336 1478//336
+f 1478//335 1502//335 1479//335
+f 1479//334 1503//334 1480//334
+f 1480//333 1504//333 1481//333
+f 1481//332 1505//332 1482//332
+f 1482//331 1506//331 1483//331
+f 1483//330 1507//330 1484//330
+f 1484//329 1508//329 1485//329
+f 1485//328 1509//328 1486//328
+f 1486//327 1510//327 1487//327
+f 1487//326 1511//326 1488//326
+f 1488//325 1512//325 1465//325
+f 1489//348 1513//348 1490//348
+f 1491//347 1490//347 1515//347
+f 1491//346 1515//346 1492//346
+f 1493//345 1492//345 1517//345
+f 1493//344 1517//344 1494//344
+f 1494//343 1518//343 1495//343
+f 1495//342 1519//342 1496//342
+f 1496//341 1520//341 1497//341
+f 1497//340 1521//340 1498//340
+f 1498//339 1522//339 1499//339
+f 1499//338 1523//338 1500//338
+f 1500//337 1524//337 1501//337
+f 1501//360 1525//360 1502//360
+f 1503//359 1502//359 1527//359
+f 1504//358 1503//358 1528//358
+f 1505//357 1504//357 1529//357
+f 1506//356 1505//356 1530//356
+f 1506//355 1530//355 1507//355
+f 1508//354 1507//354 1532//354
+f 1509//353 1508//353 1533//353
+f 1509//352 1533//352 1510//352
+f 1511//351 1510//351 1535//351
+f 1511//350 1535//350 1512//350
+f 1489//349 1512//349 1513//349
+f 1513//372 1537//372 1514//372
+f 1515//371 1514//371 1539//371
+f 1515//1219 1539//1219 1516//1219
+f 1517//369 1516//369 1541//369
+f 1517//368 1541//368 1518//368
+f 1519//367 1518//367 1543//367
+f 1520//366 1519//366 1544//366
+f 1521//365 1520//365 1545//365
+f 1521//364 1545//364 1522//364
+f 1522//1167 1546//1167 1523//1167
+f 1524//362 1523//362 1548//362
+f 1525//361 1524//361 1549//361
+f 1525//384 1549//384 1526//384
+f 1526//383 1550//383 1527//383
+f 1527//1199 1551//1199 1528//1199
+f 1528//381 1552//381 1529//381
+f 1529//380 1553//380 1530//380
+f 1530//379 1554//379 1531//379
+f 1531//378 1555//378 1532//378
+f 1532//377 1556//377 1533//377
+f 1533//376 1557//376 1534//376
+f 1535//1220 1534//1220 1559//1220
+f 1535//374 1559//374 1536//374
+f 1513//373 1536//373 1537//373
+f 1538//396 1537//396 1562//396
+f 1538//395 1562//395 1539//395
+f 1539//394 1563//394 1540//394
+f 1541//393 1540//393 1565//393
+f 1541//392 1565//392 1542//392
+f 1542//391 1566//391 1543//391
+f 1543//390 1567//390 1544//390
+f 1544//389 1568//389 1545//389
+f 1545//388 1569//388 1546//388
+f 1546//387 1570//387 1547//387
+f 1548//386 1547//386 1572//386
+f 1549//385 1548//385 1573//385
+f 1549//408 1573//408 1550//408
+f 1550//407 1574//407 1551//407
+f 1552//406 1551//406 1576//406
+f 1553//405 1552//405 1577//405
+f 1554//404 1553//404 1578//404
+f 1555//403 1554//403 1579//403
+f 1555//402 1579//402 1556//402
+f 1557//401 1556//401 1581//401
+f 1557//400 1581//400 1558//400
+f 1559//399 1558//399 1583//399
+f 1560//398 1559//398 1584//398
+f 1537//397 1560//397 1561//397
+f 1562//420 1561//420 1586//420
+f 1562//419 1586//419 1563//419
+f 1564//418 1563//418 1588//418
+f 1565//417 1564//417 1589//417
+f 1566//416 1565//416 1590//416
+f 1566//415 1590//415 1567//415
+f 1567//414 1591//414 1568//414
+f 1568//413 1592//413 1569//413
+f 1570//412 1569//412 1594//412
+f 1570//411 1594//411 1571//411
+f 1572//410 1571//410 1596//410
+f 1573//409 1572//409 1597//409
+f 1573//432 1597//432 1574//432
+f 1574//431 1598//431 1575//431
+f 1576//430 1575//430 1600//430
+f 1577//429 1576//429 1601//429
+f 1578//428 1577//428 1602//428
+f 1578//427 1602//427 1579//427
+f 1580//426 1579//426 1604//426
+f 1580//425 1604//425 1581//425
+f 1581//424 1605//424 1582//424
+f 1582//423 1606//423 1583//423
+f 1584//422 1583//422 1608//422
+f 1561//421 1584//421 1585//421
+f 1585//444 1609//444 1586//444
+f 1586//443 1610//443 1587//443
+f 1588//1203 1587//1203 1612//1203
+f 1588//441 1612//441 1589//441
+f 1590//440 1589//440 1614//440
+f 1590//439 1614//439 1591//439
+f 1592//438 1591//438 1616//438
+f 1593//437 1592//437 1617//437
+f 1594//436 1593//436 1618//436
+f 1594//1168 1618//1168 1595//1168
+f 1595//434 1619//434 1596//434
+f 1596//433 1620//433 1597//433
+f 1598//456 1597//456 1622//456
+f 1598//455 1622//455 1599//455
+f 1600//1169 1599//1169 1624//1169
+f 1600//453 1624//453 1601//453
+f 1601//452 1625//452 1602//452
+f 1602//451 1626//451 1603//451
+f 1603//450 1627//450 1604//450
+f 1605//449 1604//449 1629//449
+f 1606//448 1605//448 1630//448
+f 1606//1204 1630//1204 1607//1204
+f 1608//446 1607//446 1632//446
+f 1585//445 1608//445 1609//445
+f 1610//468 1609//468 1634//468
+f 1610//467 1634//467 1611//467
+f 1612//466 1611//466 1636//466
+f 1612//465 1636//465 1613//465
+f 1613//464 1637//464 1614//464
+f 1615//463 1614//463 1639//463
+f 1615//462 1639//462 1616//462
+f 1617//461 1616//461 1641//461
+f 1617//460 1641//460 1618//460
+f 1619//459 1618//459 1643//459
+f 1619//458 1643//458 1620//458
+f 1620//457 1644//457 1621//457
+f 1622//480 1621//480 1646//480
+f 1622//479 1646//479 1623//479
+f 1623//478 1647//478 1624//478
+f 1624//477 1648//477 1625//477
+f 1625//476 1649//476 1626//476
+f 1627//475 1626//475 1651//475
+f 1627//474 1651//474 1628//474
+f 1629//473 1628//473 1653//473
+f 1629//472 1653//472 1630//472
+f 1630//471 1654//471 1631//471
+f 1632//470 1631//470 1656//470
+f 1632//469 1656//469 1609//469
+f 1633//492 1657//492 1634//492
+f 1634//491 1658//491 1635//491
+f 1636//490 1635//490 1660//490
+f 1637//489 1636//489 1661//489
+f 1637//488 1661//488 1638//488
+f 1638//487 1662//487 1639//487
+f 1640//486 1639//486 1664//486
+f 1641//485 1640//485 1665//485
+f 1641//484 1665//484 1642//484
+f 1642//483 1666//483 1643//483
+f 1644//482 1643//482 1668//482
+f 1645//481 1644//481 1669//481
+f 1645//504 1669//504 1646//504
+f 1646//503 1670//503 1647//503
+f 1647//502 1671//502 1648//502
+f 1649//501 1648//501 1673//501
+f 1649//500 1673//500 1650//500
+f 1650//499 1674//499 1651//499
+f 1652//498 1651//498 1676//498
+f 1653//497 1652//497 1677//497
+f 1653//496 1677//496 1654//496
+f 1654//495 1678//495 1655//495
+f 1656//494 1655//494 1680//494
+f 1656//493 1680//493 1633//493
+f 1657//516 1681//516 1658//516
+f 1658//515 1682//515 1659//515
+f 1659//514 1683//514 1660//514
+f 1660//513 1684//513 1661//513
+f 1661//512 1685//512 1662//512
+f 1663//511 1662//511 1687//511
+f 1663//510 1687//510 1664//510
+f 1665//509 1664//509 1689//509
+f 1665//508 1689//508 1666//508
+f 1666//507 1690//507 1667//507
+f 1667//506 1691//506 1668//506
+f 1668//505 1692//505 1669//505
+f 1670//528 1669//528 1694//528
+f 1671//527 1670//527 1695//527
+f 1671//526 1695//526 1672//526
+f 1673//525 1672//525 1697//525
+f 1673//524 1697//524 1674//524
+f 1675//523 1674//523 1699//523
+f 1675//1221 1699//1221 1676//1221
+f 1677//521 1676//521 1701//521
+f 1678//520 1677//520 1702//520
+f 1679//519 1678//519 1703//519
+f 1680//518 1679//518 1704//518
+f 1657//517 1680//517 1681//517
+f 1681//540 1705//540 1682//540
+f 1683//539 1682//539 1707//539
+f 1684//538 1683//538 1708//538
+f 1684//537 1708//537 1685//537
+f 1686//536 1685//536 1710//536
+f 1686//535 1710//535 1687//535
+f 1687//534 1711//534 1688//534
+f 1689//533 1688//533 1713//533
+f 1689//532 1713//532 1690//532
+f 1691//531 1690//531 1715//531
+f 1691//530 1715//530 1692//530
+f 1692//529 1716//529 1693//529
+f 1694//552 1693//552 1718//552
+f 1695//551 1694//551 1719//551
+f 1695//550 1719//550 1696//550
+f 1696//549 1720//549 1697//549
+f 1697//548 1721//548 1698//548
+f 1699//547 1698//547 1723//547
+f 1700//546 1699//546 1724//546
+f 1700//545 1724//545 1701//545
+f 1702//544 1701//544 1726//544
+f 1702//543 1726//543 1703//543
+f 1703//542 1727//542 1704//542
+f 1681//541 1704//541 1705//541
+f 1705//564 1729//564 1706//564
+f 1706//563 1730//563 1707//563
+f 1708//562 1707//562 1732//562
+f 1709//561 1708//561 1733//561
+f 1710//560 1709//560 1734//560
+f 1710//559 1734//559 1711//559
+f 1712//558 1711//558 1736//558
+f 1713//557 1712//557 1737//557
+f 1714//556 1713//556 1738//556
+f 1714//555 1738//555 1715//555
+f 1715//554 1739//554 1716//554
+f 1717//553 1716//553 1741//553
+f 1717//576 1741//576 1718//576
+f 1719//575 1718//575 1743//575
+f 1719//574 1743//574 1720//574
+f 1721//573 1720//573 1745//573
+f 1721//572 1745//572 1722//572
+f 1722//571 1746//571 1723//571
+f 1724//570 1723//570 1748//570
+f 1724//569 1748//569 1725//569
+f 1725//568 1749//568 1726//568
+f 1726//567 1750//567 1727//567
+f 1728//566 1727//566 1752//566
+f 1705//565 1728//565 1729//565
+f 1729//588 1753//588 1730//588
+f 1730//587 1754//587 1731//587
+f 1732//586 1731//586 1756//586
+f 1732//585 1756//585 1733//585
+f 1733//584 1757//584 1734//584
+f 1734//583 1758//583 1735//583
+f 1735//582 1759//582 1736//582
+f 1736//581 1760//581 1737//581
+f 1737//580 1761//580 1738//580
+f 1739//579 1738//579 1763//579
+f 1739//578 1763//578 1740//578
+f 1741//577 1740//577 1765//577
+f 1741//600 1765//600 1742//600
+f 1743//599 1742//599 1767//599
+f 1743//598 1767//598 1744//598
+f 1745//597 1744//597 1769//597
+f 1746//596 1745//596 1770//596
+f 1747//595 1746//595 1771//595
+f 1748//594 1747//594 1772//594
+f 1748//593 1772//593 1749//593
+f 1750//592 1749//592 1774//592
+f 1750//591 1774//591 1751//591
+f 1752//590 1751//590 1776//590
+f 1752//589 1776//589 1729//589
+f 1753//612 1777//612 1754//612
+f 1754//611 1778//611 1755//611
+f 1755//610 1779//610 1756//610
+f 1757//609 1756//609 1781//609
+f 1757//608 1781//608 1758//608
+f 1759//607 1758//607 1783//607
+f 1759//606 1783//606 1760//606
+f 1761//605 1760//605 1785//605
+f 1762//604 1761//604 1786//604
+f 1762//603 1786//603 1763//603
+f 1763//602 1787//602 1764//602
+f 1765//601 1764//601 1789//601
+f 1765//624 1789//624 1766//624
+f 1767//623 1766//623 1791//623
+f 1768//622 1767//622 1792//622
+f 1768//621 1792//621 1769//621
+f 1769//620 1793//620 1770//620
+f 1771//619 1770//619 1795//619
+f 1771//618 1795//618 1772//618
+f 1772//617 1796//617 1773//617
+f 1773//616 1797//616 1774//616
+f 1774//615 1798//615 1775//615
+f 1776//614 1775//614 1800//614
+f 1753//613 1776//613 1777//613
+f 1778//636 1777//636 1802//636
+f 1778//635 1802//635 1779//635
+f 1779//634 1803//634 1780//634
+f 1781//633 1780//633 1805//633
+f 1782//632 1781//632 1806//632
+f 1783//1172 1782//1172 1807//1172
+f 1783//630 1807//630 1784//630
+f 1784//629 1808//629 1785//629
+f 1785//628 1809//628 1786//628
+f 1787//627 1786//627 1811//627
+f 1787//626 1811//626 1788//626
+f 1789//625 1788//625 1813//625
+f 1789//648 1813//648 1790//648
+f 1790//647 1814//647 1791//647
+f 1791//646 1815//646 1792//646
+f 1792//645 1816//645 1793//645
+f 1794//644 1793//644 1818//644
+f 1794//643 1818//643 1795//643
+f 1795//1222 1819//1222 1796//1222
+f 1796//641 1820//641 1797//641
+f 1797//640 1821//640 1798//640
+f 1799//639 1798//639 1823//639
+f 1800//638 1799//638 1824//638
+f 1800//637 1824//637 1777//637
+f 1802//660 1801//660 1826//660
+f 1802//659 1826//659 1803//659
+f 1803//658 1827//658 1804//658
+f 1805//657 1804//657 1829//657
+f 1805//656 1829//656 1806//656
+f 1806//655 1830//655 1807//655
+f 1807//654 1831//654 1808//654
+f 1808//653 1832//653 1809//653
+f 1809//652 1833//652 1810//652
+f 1810//651 1834//651 1811//651
+f 1811//650 1835//650 1812//650
+f 1812//649 1836//649 1813//649
+f 1814//672 1813//672 1838//672
+f 1815//671 1814//671 1839//671
+f 1816//670 1815//670 1840//670
+f 1817//669 1816//669 1841//669
+f 1818//668 1817//668 1842//668
+f 1819//667 1818//667 1843//667
+f 1820//666 1819//666 1844//666
+f 1821//665 1820//665 1845//665
+f 1821//664 1845//664 1822//664
+f 1823//663 1822//663 1847//663
+f 1824//662 1823//662 1848//662
+f 1824//661 1848//661 1801//661
+f 1826//684 1825//684 1850//684
+f 1826//683 1850//683 1827//683
+f 1827//682 1851//682 1828//682
+f 1829//681 1828//681 1853//681
+f 1830//680 1829//680 1854//680
+f 1831//679 1830//679 1855//679
+f 1832//678 1831//678 1856//678
+f 1832//677 1856//677 1833//677
+f 1834//676 1833//676 1858//676
+f 1835//675 1834//675 1859//675
+f 1835//674 1859//674 1836//674
+f 1836//673 1860//673 1837//673
+f 1838//696 1837//696 1862//696
+f 1839//695 1838//695 1863//695
+f 1839//694 1863//694 1840//694
+f 1840//693 1864//693 1841//693
+f 1842//692 1841//692 1866//692
+f 1842//691 1866//691 1843//691
+f 1844//690 1843//690 1868//690
+f 1844//689 1868//689 1845//689
+f 1845//688 1869//688 1846//688
+f 1847//687 1846//687 1871//687
+f 1848//686 1847//686 1872//686
+f 1848//685 1872//685 1825//685
+f 1849//708 1873//708 1850//708
+f 1850//707 1874//707 1851//707
+f 1851//706 1875//706 1852//706
+f 1852//705 1876//705 1853//705
+f 1854//704 1853//704 1878//704
+f 1854//703 1878//703 1855//703
+f 1856//702 1855//702 1880//702
+f 1856//701 1880//701 1857//701
+f 1857//700 1881//700 1858//700
+f 1858//1174 1882//1174 1859//1174
+f 1859//698 1883//698 1860//698
+f 1861//697 1860//697 1885//697
+f 1861//720 1885//720 1862//720
+f 1863//719 1862//719 1887//719
+f 1864//1175 1863//1175 1888//1175
+f 1865//717 1864//717 1889//717
+f 1866//716 1865//716 1890//716
+f 1866//715 1890//715 1867//715
+f 1868//714 1867//714 1892//714
+f 1868//713 1892//713 1869//713
+f 1870//712 1869//712 1894//712
+f 1871//711 1870//711 1895//711
+f 1871//710 1895//710 1872//710
+f 1872//709 1896//709 1849//709
+f 1873//732 1897//732 1874//732
+f 1875//731 1874//731 1899//731
+f 1876//730 1875//730 1900//730
+f 1877//729 1876//729 1901//729
+f 1878//728 1877//728 1902//728
+f 1879//727 1878//727 1903//727
+f 1880//726 1879//726 1904//726
+f 1881//725 1880//725 1905//725
+f 1881//724 1905//724 1882//724
+f 1883//723 1882//723 1907//723
+f 1884//722 1883//722 1908//722
+f 1884//721 1908//721 1885//721
+f 1885//744 1909//744 1886//744
+f 1886//743 1910//743 1887//743
+f 1887//742 1911//742 1888//742
+f 1888//741 1912//741 1889//741
+f 1889//740 1913//740 1890//740
+f 1890//739 1914//739 1891//739
+f 1891//738 1915//738 1892//738
+f 1892//737 1916//737 1893//737
+f 1893//736 1917//736 1894//736
+f 1895//735 1894//735 1919//735
+f 1895//734 1919//734 1896//734
+f 1873//733 1896//733 1897//733
+f 1897//756 1921//756 1898//756
+f 1899//755 1898//755 1923//755
+f 1899//754 1923//754 1900//754
+f 1900//753 1924//753 1901//753
+f 1901//752 1925//752 1902//752
+f 1902//751 1926//751 1903//751
+f 1903//750 1927//750 1904//750
+f 1905//749 1904//749 1929//749
+f 1905//748 1929//748 1906//748
+f 1907//747 1906//747 1931//747
+f 1907//746 1931//746 1908//746
+f 1909//745 1908//745 1933//745
+f 1909//768 1933//768 1910//768
+f 1911//767 1910//767 1935//767
+f 1911//766 1935//766 1912//766
+f 1913//765 1912//765 1937//765
+f 1913//764 1937//764 1914//764
+f 1915//763 1914//763 1939//763
+f 1916//762 1915//762 1940//762
+f 1916//761 1940//761 1917//761
+f 1918//760 1917//760 1942//760
+f 1919//759 1918//759 1943//759
+f 1919//758 1943//758 1920//758
+f 1897//757 1920//757 1921//757
+f 1922//780 1921//780 1946//780
+f 1923//779 1922//779 1947//779
+f 1924//778 1923//778 1948//778
+f 1925//777 1924//777 1949//777
+f 1925//776 1949//776 1926//776
+f 1927//775 1926//775 1951//775
+f 1928//774 1927//774 1952//774
+f 1928//773 1952//773 1929//773
+f 1930//772 1929//772 1954//772
+f 1931//771 1930//771 1955//771
+f 1931//770 1955//770 1932//770
+f 1933//769 1932//769 1957//769
+f 1933//792 1957//792 1934//792
+f 1935//791 1934//791 1959//791
+f 1935//790 1959//790 1936//790
+f 1936//789 1960//789 1937//789
+f 1937//788 1961//788 1938//788
+f 1938//787 1962//787 1939//787
+f 1939//786 1963//786 1940//786
+f 1941//785 1940//785 1965//785
+f 1941//784 1965//784 1942//784
+f 1942//783 1966//783 1943//783
+f 1943//782 1967//782 1944//782
+f 1944//781 1968//781 1921//781
+f 1945//804 1969//804 1946//804
+f 1947//803 1946//803 1971//803
+f 1947//802 1971//802 1948//802
+f 1949//801 1948//801 1973//801
+f 1949//800 1973//800 1950//800
+f 1950//799 1974//799 1951//799
+f 1952//798 1951//798 1976//798
+f 1953//797 1952//797 1977//797
+f 1953//796 1977//796 1954//796
+f 1955//795 1954//795 1979//795
+f 1955//794 1979//794 1956//794
+f 1956//793 1980//793 1957//793
+f 1958//816 1957//816 1982//816
+f 1959//815 1958//815 1983//815
+f 1959//814 1983//814 1960//814
+f 1960//813 1984//813 1961//813
+f 1961//812 1985//812 1962//812
+f 1962//811 1986//811 1963//811
+f 1964//810 1963//810 1988//810
+f 1964//809 1988//809 1965//809
+f 1965//808 1989//808 1966//808
+f 1967//807 1966//807 1991//807
+f 1967//806 1991//806 1968//806
+f 1945//805 1968//805 1969//805
+f 1969//828 1993//828 1970//828
+f 1971//827 1970//827 1995//827
+f 1971//826 1995//826 1972//826
+f 1972//825 1996//825 1973//825
+f 1974//824 1973//824 1998//824
+f 1975//823 1974//823 1999//823
+f 1975//822 1999//822 1976//822
+f 1976//821 2000//821 1977//821
+f 1977//820 2001//820 1978//820
+f 1978//819 2002//819 1979//819
+f 1979//818 2003//818 1980//818
+f 1980//817 2004//817 1981//817
+f 1982//840 1981//840 2006//840
+f 1983//839 1982//839 2007//839
+f 1984//838 1983//838 2008//838
+f 1985//837 1984//837 2009//837
+f 1985//836 2009//836 1986//836
+f 1987//835 1986//835 2011//835
+f 1987//834 2011//834 1988//834
+f 1988//833 2012//833 1989//833
+f 1990//832 1989//832 2014//832
+f 1991//831 1990//831 2015//831
+f 1991//830 2015//830 1992//830
+f 1992//829 2016//829 1969//829
+f 1993//852 2017//852 1994//852
+f 1995//851 1994//851 2019//851
+f 1995//850 2019//850 1996//850
+f 1997//849 1996//849 2021//849
+f 1997//848 2021//848 1998//848
+f 1999//847 1998//847 2023//847
+f 2000//846 1999//846 2024//846
+f 2001//845 2000//845 2025//845
+f 2002//844 2001//844 2026//844
+f 2002//843 2026//843 2003//843
+f 2004//842 2003//842 2028//842
+f 2004//1223 2028//1223 2005//1223
+f 2006//1184 2005//1184 2030//1184
+f 2006//863 2030//863 2007//863
+f 2007//862 2031//862 2008//862
+f 2008//861 2032//861 2009//861
+f 2009//860 2033//860 2010//860
+f 2010//859 2034//859 2011//859
+f 2012//858 2011//858 2036//858
+f 2013//857 2012//857 2037//857
+f 2013//856 2037//856 2014//856
+f 2015//855 2014//855 2039//855
+f 2015//854 2039//854 2016//854
+f 2016//1224 2040//1224 1993//1224
+f 2017//876 2041//876 2018//876
+f 2019//875 2018//875 2043//875
+f 2019//874 2043//874 2020//874
+f 2021//873 2020//873 2045//873
+f 2021//872 2045//872 2022//872
+f 2022//871 2046//871 2023//871
+f 2024//870 2023//870 2048//870
+f 2025//869 2024//869 2049//869
+f 2025//868 2049//868 2026//868
+f 2026//867 2050//867 2027//867
+f 2028//866 2027//866 2052//866
+f 2028//865 2052//865 2029//865
+f 2030//1212 2029//1212 2054//1212
+f 2030//887 2054//887 2031//887
+f 2032//886 2031//886 2056//886
+f 2032//885 2056//885 2033//885
+f 2033//884 2057//884 2034//884
+f 2035//883 2034//883 2059//883
+f 2035//882 2059//882 2036//882
+f 2037//881 2036//881 2061//881
+f 2037//880 2061//880 2038//880
+f 2039//879 2038//879 2063//879
+f 2039//878 2063//878 2040//878
+f 2017//1211 2040//1211 2041//1211
+f 2041//900 2065//900 2042//900
+f 2043//1185 2042//1185 2067//1185
+f 2043//898 2067//898 2044//898
+f 2044//897 2068//897 2045//897
+f 2046//896 2045//896 2070//896
+f 2046//895 2070//895 2047//895
+f 2047//894 2071//894 2048//894
+f 2049//893 2048//893 2073//893
+f 2049//892 2073//892 2050//892
+f 2051//891 2050//891 2075//891
+f 2051//890 2075//890 2052//890
+f 2052//889 2076//889 2053//889
+f 2054//912 2053//912 2078//912
+f 2055//911 2054//911 2079//911
+f 2055//910 2079//910 2056//910
+f 2057//909 2056//909 2081//909
+f 2057//908 2081//908 2058//908
+f 2059//907 2058//907 2083//907
+f 2060//906 2059//906 2084//906
+f 2060//905 2084//905 2061//905
+f 2061//904 2085//904 2062//904
+f 2063//903 2062//903 2087//903
+f 2063//902 2087//902 2064//902
+f 2064//901 2088//901 2041//901
+f 2065//924 2089//924 2066//924
+f 2067//923 2066//923 2091//923
+f 2067//922 2091//922 2068//922
+f 2069//921 2068//921 2093//921
+f 2070//920 2069//920 2094//920
+f 2071//919 2070//919 2095//919
+f 2071//918 2095//918 2072//918
+f 2072//917 2096//917 2073//917
+f 2073//916 2097//916 2074//916
+f 2074//915 2098//915 2075//915
+f 2076//914 2075//914 2100//914
+f 2076//913 2100//913 2077//913
+f 2077//936 2101//936 2078//936
+f 2078//935 2102//935 2079//935
+f 2080//934 2079//934 2104//934
+f 2081//933 2080//933 2105//933
+f 2082//932 2081//932 2106//932
+f 2083//931 2082//931 2107//931
+f 2083//930 2107//930 2084//930
+f 2084//929 2108//929 2085//929
+f 2085//928 2109//928 2086//928
+f 2087//927 2086//927 2111//927
+f 2087//926 2111//926 2088//926
+f 2065//925 2088//925 2089//925
+f 2090//948 2089//948 2114//948
+f 2091//947 2090//947 2115//947
+f 2091//946 2115//946 2092//946
+f 2092//945 2116//945 2093//945
+f 2093//944 2117//944 2094//944
+f 2094//943 2118//943 2095//943
+f 2095//942 2119//942 2096//942
+f 2096//941 2120//941 2097//941
+f 2098//940 2097//940 2122//940
+f 2099//1187 2098//1187 2123//1187
+f 2100//938 2099//938 2124//938
+f 2100//937 2124//937 2101//937
+f 2102//960 2101//960 2126//960
+f 2102//959 2126//959 2103//959
+f 2103//958 2127//958 2104//958
+f 2104//957 2128//957 2105//957
+f 2106//956 2105//956 2130//956
+f 2107//955 2106//955 2131//955
+f 2108//954 2107//954 2132//954
+f 2109//953 2108//953 2133//953
+f 2110//952 2109//952 2134//952
+f 2111//951 2110//951 2135//951
+f 2111//950 2135//950 2112//950
+f 2112//949 2136//949 2089//949
+f 2114//972 2113//972 2138//972
+f 2114//1225 2138//1225 2115//1225
+f 2116//970 2115//970 2140//970
+f 2117//969 2116//969 2141//969
+f 2117//968 2141//968 2118//968
+f 2118//967 2142//967 2119//967
+f 2120//966 2119//966 2144//966
+f 2120//965 2144//965 2121//965
+f 2121//964 2145//964 2122//964
+f 2122//963 2146//963 2123//963
+f 2123//962 2147//962 2124//962
+f 2125//961 2124//961 2149//961
+f 2125//984 2149//984 2126//984
+f 2126//1226 2150//1226 2127//1226
+f 2128//982 2127//982 2152//982
+f 2129//981 2128//981 2153//981
+f 2130//980 2129//980 2154//980
+f 2130//979 2154//979 2131//979
+f 2132//978 2131//978 2156//978
+f 2132//977 2156//977 2133//977
+f 2133//976 2157//976 2134//976
+f 2134//975 2158//975 2135//975
+f 2135//1227 2159//1227 2136//1227
+f 2136//973 2160//973 2113//973
+f 2138//996 2137//996 2162//996
+f 2138//995 2162//995 2139//995
+f 2139//994 2163//994 2140//994
+f 2140//993 2164//993 2141//993
+f 2141//992 2165//992 2142//992
+f 2142//991 2166//991 2143//991
+f 2143//990 2167//990 2144//990
+f 2144//989 2168//989 2145//989
+f 2146//988 2145//988 2170//988
+f 2146//987 2170//987 2147//987
+f 2148//986 2147//986 2172//986
+f 2149//985 2148//985 2173//985
+f 2149//1008 2173//1008 2150//1008
+f 2150//1007 2174//1007 2151//1007
+f 2152//1006 2151//1006 2176//1006
+f 2152//1005 2176//1005 2153//1005
+f 2154//1004 2153//1004 2178//1004
+f 2155//1003 2154//1003 2179//1003
+f 2156//1002 2155//1002 2180//1002
+f 2156//1001 2180//1001 2157//1001
+f 2158//1000 2157//1000 2182//1000
+f 2158//999 2182//999 2159//999
+f 2160//998 2159//998 2184//998
+f 2160//997 2184//997 2137//997
+f 2162//1020 2161//1020 2186//1020
+f 2162//1019 2186//1019 2163//1019
+f 2164//1018 2163//1018 2188//1018
+f 2164//1017 2188//1017 2165//1017
+f 2166//1016 2165//1016 2190//1016
+f 2167//1015 2166//1015 2191//1015
+f 2168//1014 2167//1014 2192//1014
+f 2169//1013 2168//1013 2193//1013
+f 2170//1012 2169//1012 2194//1012
+f 2170//1191 2194//1191 2171//1191
+f 2171//1010 2195//1010 2172//1010
+f 2172//1009 2196//1009 2173//1009
+f 2174//1032 2173//1032 2198//1032
+f 2174//1031 2198//1031 2175//1031
+f 2175//1192 2199//1192 2176//1192
+f 2176//1029 2200//1029 2177//1029
+f 2177//1028 2201//1028 2178//1028
+f 2178//1027 2202//1027 2179//1027
+f 2179//1026 2203//1026 2180//1026
+f 2180//1025 2204//1025 2181//1025
+f 2181//1024 2205//1024 2182//1024
+f 2182//1023 2206//1023 2183//1023
+f 2184//1022 2183//1022 2208//1022
+f 2184//1021 2208//1021 2161//1021
+f 2186//1044 2185//1044 2210//1044
+f 2186//1043 2210//1043 2187//1043
+f 2187//1042 2211//1042 2188//1042
+f 2188//1041 2212//1041 2189//1041
+f 2189//1040 2213//1040 2190//1040
+f 2190//1039 2214//1039 2191//1039
+f 2191//1038 2215//1038 2192//1038
+f 2193//1037 2192//1037 2217//1037
+f 2194//1036 2193//1036 2218//1036
+f 2194//1035 2218//1035 2195//1035
+f 2196//1034 2195//1034 2220//1034
+f 2196//1033 2220//1033 2197//1033
+f 2198//1056 2197//1056 2222//1056
+f 2198//1055 2222//1055 2199//1055
+f 2200//1054 2199//1054 2224//1054
+f 2200//1053 2224//1053 2201//1053
+f 2202//1052 2201//1052 2226//1052
+f 2203//1051 2202//1051 2227//1051
+f 2204//1050 2203//1050 2228//1050
+f 2205//1049 2204//1049 2229//1049
+f 2205//1048 2229//1048 2206//1048
+f 2207//1047 2206//1047 2231//1047
+f 2208//1046 2207//1046 2232//1046
+f 2208//1045 2232//1045 2185//1045
+f 2210//1068 2209//1068 2234//1068
+f 2211//1067 2210//1067 2235//1067
+f 2211//1066 2235//1066 2212//1066
+f 2213//1065 2212//1065 2237//1065
+f 2213//1064 2237//1064 2214//1064
+f 2214//1063 2238//1063 2215//1063
+f 2215//1062 2239//1062 2216//1062
+f 2216//1061 2240//1061 2217//1061
+f 2217//1060 2241//1060 2218//1060
+f 2218//1059 2242//1059 2219//1059
+f 2219//1058 2243//1058 2220//1058
+f 2220//1057 2244//1057 2221//1057
+f 2221//1080 2245//1080 2222//1080
+f 2223//1079 2222//1079 2247//1079
+f 2224//1078 2223//1078 2248//1078
+f 2224//1077 2248//1077 2225//1077
+f 2226//1076 2225//1076 2250//1076
+f 2226//1075 2250//1075 2227//1075
+f 2228//1074 2227//1074 2252//1074
+f 2229//1073 2228//1073 2253//1073
+f 2230//1072 2229//1072 2254//1072
+f 2231//1071 2230//1071 2255//1071
+f 2231//1070 2255//1070 2232//1070
+f 2232//1069 2256//1069 2209//1069
+f 2233//1092 2257//1092 2234//1092
+f 2234//1091 2258//1091 2235//1091
+f 2236//1090 2235//1090 2260//1090
+f 2237//1089 2236//1089 2261//1089
+f 2238//1088 2237//1088 2262//1088
+f 2239//1087 2238//1087 2263//1087
+f 2239//1086 2263//1086 2240//1086
+f 2241//1085 2240//1085 2265//1085
+f 2242//1084 2241//1084 2266//1084
+f 2242//1083 2266//1083 2243//1083
+f 2243//1082 2267//1082 2244//1082
+f 2245//1081 2244//1081 2269//1081
+f 2245//1104 2269//1104 2246//1104
+f 2246//1103 2270//1103 2247//1103
+f 2247//1102 2271//1102 2248//1102
+f 2249//1101 2248//1101 2273//1101
+f 2249//1100 2273//1100 2250//1100
+f 2251//1099 2250//1099 2275//1099
+f 2251//1098 2275//1098 2252//1098
+f 2252//1097 2276//1097 2253//1097
+f 2253//1096 2277//1096 2254//1096
+f 2254//1095 2278//1095 2255//1095
+f 2256//1094 2255//1094 2280//1094
+f 2233//1093 2256//1093 2257//1093
+f 2258//1116 2257//1116 2282//1116
+f 2258//1115 2282//1115 2259//1115
+f 2259//1114 2283//1114 2260//1114
+f 2260//1113 2284//1113 2261//1113
+f 2261//1112 2285//1112 2262//1112
+f 2262//1111 2286//1111 2263//1111
+f 2263//1110 2287//1110 2264//1110
+f 2264//1109 2288//1109 2265//1109
+f 2265//1108 2289//1108 2266//1108
+f 2266//1107 2290//1107 2267//1107
+f 2267//1106 2291//1106 2268//1106
+f 2268//1105 2292//1105 2269//1105
+f 2270//1128 2269//1128 2294//1128
+f 2271//1127 2270//1127 2295//1127
+f 2272//1126 2271//1126 2296//1126
+f 2273//1125 2272//1125 2297//1125
+f 2274//1124 2273//1124 2298//1124
+f 2275//1123 2274//1123 2299//1123
+f 2276//1122 2275//1122 2300//1122
+f 2277//1121 2276//1121 2301//1121
+f 2278//1120 2277//1120 2302//1120
+f 2278//1119 2302//1119 2279//1119
+f 2280//1118 2279//1118 2304//1118
+f 2280//1117 2304//1117 2257//1117
+f 2281//1140 1//1140 2282//1140
+f 2282//1139 2//1139 2283//1139
+f 2283//1138 3//1138 2284//1138
+f 2284//1137 4//1137 2285//1137
+f 2285//1136 5//1136 2286//1136
+f 2286//1135 6//1135 2287//1135
+f 2288//1134 2287//1134 8//1134
+f 2288//1133 8//1133 2289//1133
+f 2289//1132 9//1132 2290//1132
+f 2291//1131 2290//1131 11//1131
+f 2292//1130 2291//1130 12//1130
+f 2293//1129 2292//1129 13//1129
+f 2293//1152 13//1152 2294//1152
+f 2294//1151 14//1151 2295//1151
+f 2295//1150 15//1150 2296//1150
+f 2297//1149 2296//1149 17//1149
+f 2298//1148 2297//1148 18//1148
+f 2298//1147 18//1147 2299//1147
+f 2299//1146 19//1146 2300//1146
+f 2300//1145 20//1145 2301//1145
+f 2301//1144 21//1144 2302//1144
+f 2303//1143 2302//1143 23//1143
+f 2303//1142 23//1142 2304//1142
+f 2304//1141 24//1141 2281//1141
diff --git a/apps/CtsVerifier/res/raw/ring_sound.wav b/apps/CtsVerifier/res/raw/ring_sound.wav
new file mode 100644
index 0000000..763ef14
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/ring_sound.wav
Binary files differ
diff --git a/apps/CtsVerifier/res/values/colors.xml b/apps/CtsVerifier/res/values/colors.xml
index c855d5f..b026260 100644
--- a/apps/CtsVerifier/res/values/colors.xml
+++ b/apps/CtsVerifier/res/values/colors.xml
@@ -12,4 +12,12 @@
     <color name="snsr_warning">#75540C</color>
     <color name="snsr_information_background">#D0D2F6</color>
     <color name="snsr_information">#41576B</color>
+
+    <!-- 6DoF test colors -->
+    <item name="textPrimary" type="color">#FFFFFF</item>
+    <item name="primary" type="color">#43A047</item>
+    <item name="primaryPressed" type="color">#81C784</item>
+    <color name="backgroundGrey">#303030</color>
+    <color name="textSecondary">#B3FFFFFF</color>
+    <color name="yellow">#C0FFFF00</color>
 </resources>
diff --git a/apps/CtsVerifier/res/values/dimens.xml b/apps/CtsVerifier/res/values/dimens.xml
index 8df5b35..0f1ec44 100644
--- a/apps/CtsVerifier/res/values/dimens.xml
+++ b/apps/CtsVerifier/res/values/dimens.xml
@@ -38,4 +38,7 @@
 
     <dimen name="js_padding">10dp</dimen>
 
-</resources>
\ No newline at end of file
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index ef77c84..5cd2cb4 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2860,4 +2860,138 @@
     <string name="audio_frequency_unprocessed_test1_btn">Test 1</string>
     <string name="audio_frequency_unprocessed_results_text">Results...</string>
 
+    <!-- Strings for 6DoF test -->
+    <string name="six_dof_test">6DoF Test</string>
+    <string name="action_settings">Settings</string>
+    <string name="start">Start</string>
+    <string name="motion_tracking_permission">"Motion Tracking permission needed!"</string>
+    <string name="translations">Translations:</string>
+    <string name="rotations">Rotations:</string>
+    <string name="action_place_marker">Place Marker</string>
+    <string name="markers">Markers:\n</string>
+    <string name="title_activity_cts">CTSActivity</string>
+    <string name="stop">Stop!</string>
+    <string name="stop_message">Mark where you are standing with something like a piece of card and
+        then press ready to record this waypoint
+    </string>
+    <string name="ready">Ready</string>
+    <string name="initial">First Waypoint</string>
+    <string name="phase1_initial_message">When you are ready to place your first waypoint, place a
+        marker at the devices current location. Use something that will allow you to put the device
+        in the exact same position and orientation on the second lap. Then, while the device is on
+        the marker, click the turquoise action button to record the first waypoint.\n\nStart walking
+        in a direction. The button will appear again when you have walked far enough. Place a marker
+        at the device\'s location and press the button to record a waypoint. You cannot place
+        waypoints in a straight line, so for your 3rd waypoint turn 90 degrees and walk in a
+        direction that will make a triangle out of your 3 waypoints.
+    </string>
+    <string name="phase2_initial_message">You now need to visit each waypoint, clicking the
+        turquoise action button at each one. You need to reach each waypoint in 20 seconds. While
+        you are on your way to the waypoints, the camera preview will rotate. You will need to
+        rotate the device to match the rotation of the camera preview. A box will be shown to help
+        you. It shows the device\'s current rotation and will change colour based on whether you are
+        close enough to the required rotation. Red if you are failing, green if you are passing.
+        When you have reached the next waypoint, the device can be returned to it\'s original
+        rotation.
+    </string>
+    <string name="last">Go back to the first waypoint</string>
+    <string name="last_message">Now go back to the first waypoint and press ready to finish the
+        first lap.
+    </string>
+    <string name="got_it">Got it!</string>
+    <string name="lap2_instructions">Now, go to each waypoint (including your initial
+        one) and click the turquoise action button. Then move on to the next waypoint and do the
+        same.\nThe last waypoint should be the first waypoint again.
+    </string>
+    <string name="test1_pass2">Pass 2</string>
+    <string name="results">Results</string>
+    <string name="overall_instructions">These tests are designed to verify the correctness and
+        accuracy of a 6DoF enabled device. There will be 3 phases to these tests, each testing a
+        different part of 6DOF functionality.
+    </string>
+    <string name="phase1_description">This first test will test the accuracy of the device. It will
+        ask you to mark out 4 waypoints and then return to the original waypoint to complete the
+        lap. After this you will then need to do another lap without any HUD information. At the
+        end, the pairs of waypoints and the path you travelled will be compared and you will be
+        given a result.
+    </string>
+    <string name="phase2_description">This test will test the robustness of the device. Using the
+        same 4 waypoints as before, you will need to do a lap, reaching each waypoint in the
+        allotted time.\nWhile you are on your way to the waypoints, the camera preview will rotate.
+        You will need to rotate the device to match the rotation of the camera preview. A box will
+        be shown to help you. It shows the device\'s current rotation and will change colour based
+        on whether you are close enough to the required rotation. Red if you are failing, green if
+        you are passing. When you have reached the next waypoint, the device can be returned to
+        it\'s original rotation.
+    </string>
+    <string name="phase3_description">Now we will test the AR capability of the device. Again, you
+        will need to do a lap of the waypoints, but this time between each waypoint the device will
+        overlay hoops that you must pass the device through as you go along.
+    </string>
+    <string name="distance">Distance from last waypoint:</string>
+    <string name="obj_return_to_initial_waypoint">Return to initial waypoint</string>
+    <string name="waypointPlaced">Waypoint placed!</string>
+    <string name="undo">undo</string>
+    <string name="distance_remaining">Distance Remaining:\n</string>
+    <string name="waypoint_differences">Waypoints</string>
+    <string name="path_differences">Paths</string>
+    <string name="error_distance">Not far away enough from other waypoints!</string>
+    <string name="error_area">Not enough area covered.</string>
+    <string name="passed">Passed!</string>
+    <string name="failed">Failed!</string>
+    <string name="test_failed">Test Failed!</string>
+    <string name="error_start_point">Not close enough to initial waypoint!</string>
+    <string name="waypoint_distance">Waypoint %1$s: %2$s</string>
+    <string name="total">Total %1$s</string>
+    <string name="path">Path %1$s: %2$s</string>
+    <string name="fail">Fail</string>
+    <string name="pass">Pass</string>
+    <string name="info">Info</string>
+    <string name="coming_soon">Coming soon!</string>
+    <string name="motion_tracking_invalid_state">Motion Tracking has entered an invalid state
+    </string>
+    <string name="action_xml">XML</string>
+    <string name="error_null_fragment">UI fragment was null, couldn\'t do callback to listener
+    </string>
+    <string name="error_retained_fragment_null">DataFragment is null</string>
+    <string name="time_remaining">%1$s seconds remaining to get to next waypoint</string>
+    <string name="action_skip_to_2nd">Skip to 2nd Test</string>
+    <string name="failed_pause_resume">Test Failed because Test Activity was paused</string>
+    <string name="action_overlapping_outlines">Overlapping Outlines</string>
+    <string name="action_overlapping_filled">Overlapping Filled</string>
+    <string name="time">Time</string>
+    <string name="rotation_result">Rotation</string>
+    <string name="action_separate_outlines">Separate Outlines</string>
+    <string name="action_separate_filled">Separate Filled</string>
+    <string name="action_one">One Rectangle</string>
+    <string name="rotation_mode">Change rotation mode</string>
+    <string name="phase3_initial_message">Go through the rings as you visit waypoints.</string>
+    <string name="rings">Rings</string>
+    <string name="rings_entered">Rings collected %1$s/%2$s</string>
+    <string name="error_rings_not_entered">You haven\'t collected all the rings in this path!
+    </string>
+    <string name="save">Save</string>
+
+    <string-array name="initial_waypoint">
+        <item>Find a place for your first waypoint</item>
+        <item>Go to initial waypoint</item>
+    </string-array>
+
+    <string-array name="next_waypoint">
+        <item>Find a suitable place for waypoint 0</item>
+        <item>Go to waypoint 0</item>
+    </string-array>
+
+    <string-array name="phase">
+        <item>Phase 1</item>
+        <item>Phase 2</item>
+        <item>Phase 3</item>
+    </string-array>
+
+    <string-array name="phase_descriptions">
+        <item>@string/phase1_description</item>
+        <item>@string/phase2_description</item>
+        <item>@string/phase3_description</item>
+    </string-array>
+
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Activities/StartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Activities/StartActivity.java
new file mode 100644
index 0000000..ab8d084
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Activities/StartActivity.java
@@ -0,0 +1,89 @@
+/*
+ * 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.verifier.sensors.sixdof.Activities;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.Utils.ReportExporter;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.app.Activity;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+/**
+ * Launcher activity that gives brief instructions of tests.
+ */
+public class StartActivity extends PassFailButtons.Activity {
+    private Button mBtnStart;
+
+    // Unique code that ensures we get the result from the activity that want to get a result
+    private static final int REQUEST_CODE_6DOF = 5555;
+
+    public enum ResultCode {
+        FAILED_PAUSE_AND_RESUME,
+        FAILED,
+        PASSED
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_start);
+
+        mBtnStart = (Button) findViewById(R.id.btnStart);
+        mBtnStart.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                startPhase1();
+            }
+        });
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    private void startPhase1() {
+        Intent startPhase1 = new Intent(this, TestActivity.class);
+        startActivityForResult(startPhase1, REQUEST_CODE_6DOF);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        // Check which request we're responding to.
+        if (requestCode == REQUEST_CODE_6DOF) {
+            if (resultCode == RESULT_CANCELED) {
+                Toast.makeText(this, R.string.test_failed, Toast.LENGTH_SHORT).show();
+            } else { // RESULT_OK
+                ResultCode result = (ResultCode) data.getSerializableExtra(TestActivity.EXTRA_RESULT_ID);
+                if (result == ResultCode.FAILED_PAUSE_AND_RESUME) {
+                    Toast.makeText(this, R.string.failed_pause_resume, Toast.LENGTH_SHORT).show();
+                } else if (result == ResultCode.FAILED) {
+                    Toast.makeText(this, R.string.failed, Toast.LENGTH_SHORT).show();
+                } else if (result == ResultCode.PASSED) {
+                    Toast.makeText(this, R.string.passed, Toast.LENGTH_SHORT).show();
+                }
+
+                String testReport = data.getStringExtra(TestActivity.EXTRA_REPORT);
+                new ReportExporter(this, testReport).execute();
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Activities/TestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Activities/TestActivity.java
new file mode 100644
index 0000000..9ca5f2c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Activities/TestActivity.java
@@ -0,0 +1,457 @@
+/*
+ * 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.verifier.sensors.sixdof.Activities;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.Activities.StartActivity.ResultCode;
+import com.android.cts.verifier.sensors.sixdof.Fragments.AccuracyFragment;
+import com.android.cts.verifier.sensors.sixdof.Fragments.ComplexMovementFragment;
+import com.android.cts.verifier.sensors.sixdof.Fragments.DataFragment;
+import com.android.cts.verifier.sensors.sixdof.Fragments.PhaseStartFragment;
+import com.android.cts.verifier.sensors.sixdof.Fragments.RobustnessFragment;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.AccuracyListener;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.BaseUiListener;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.ComplexMovementListener;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.RobustnessListener;
+import com.android.cts.verifier.sensors.sixdof.Utils.ReportExporter;
+import com.android.cts.verifier.sensors.sixdof.Utils.TestReport;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager.Lap;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.RotationData;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint;
+import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.PoseProvider;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.AlertDialog;
+import android.app.Activity;
+import android.util.Log;
+import android.view.Display;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.Surface;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Main Activity for 6DOF tests Handles calls between UI fragments and the Data fragment. The
+ * controller in the MVC structure.
+ */
+public class TestActivity extends Activity implements BaseUiListener, AccuracyListener,
+        RobustnessListener, ComplexMovementListener {
+
+    private static final String TAG = "TestActivity";
+    private static final String TAG_DATA_FRAGMENT = "data_fragment";
+    public static final String EXTRA_RESULT_ID = "extraResult";
+    public static final String EXTRA_REPORT = "extraReport";
+    public static final String EXTRA_ON_RESTART = "6dof_verifier_restart";
+    public static final Object POSE_LOCK = new Object();
+
+    private DataFragment mDataFragment;
+
+    private BaseUiListener mUiListener;
+    private AccuracyListener mAccuracyListener;
+    private RobustnessListener mRobustnessListener;
+    private ComplexMovementListener mComplexMovementListener;
+
+    private CTSTest mCurrentTest = CTSTest.ACCURACY;
+
+    private boolean mHasBeenPaused = false;
+
+    public enum CTSTest {
+        ACCURACY,
+        ROBUSTNESS,
+        COMPLEX_MOVEMENT
+    }
+
+    /**
+     * Initialises camera preview, looks for a retained data fragment if we have one and adds UI
+     * fragment.
+     */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // If we are restarting, kill the test as data is invalid.
+        if (savedInstanceState != null) {
+            if (savedInstanceState.getBoolean(EXTRA_ON_RESTART)) {
+                Intent intent = this.getIntent();
+                intent.putExtra(EXTRA_RESULT_ID, ResultCode.FAILED_PAUSE_AND_RESUME);
+                this.setResult(RESULT_OK, intent);
+                finish();
+            }
+        }
+
+        setContentView(R.layout.activity_cts);
+
+        // Add the first instructions fragment.
+        Fragment fragment = PhaseStartFragment.newInstance(CTSTest.ACCURACY);
+        FragmentManager fragmentManager = getFragmentManager();
+        FragmentTransaction transaction = fragmentManager.beginTransaction();
+        transaction.replace(R.id.contentFragment, fragment);
+        transaction.commit();
+
+        mDataFragment = new DataFragment();
+        fragmentManager.beginTransaction().add(mDataFragment, TAG_DATA_FRAGMENT).commit();
+
+        // Lock the screen to its current rotation
+        lockRotation();
+    }
+
+    /**
+     * Lock the orientation of the device in its current state.
+     */
+    private void lockRotation() {
+        final Display display = getWindowManager().getDefaultDisplay();
+        int naturalOrientation = Configuration.ORIENTATION_LANDSCAPE;
+        int configOrientation = getResources().getConfiguration().orientation;
+        switch (display.getRotation()) {
+            case Surface.ROTATION_0:
+            case Surface.ROTATION_180:
+                // We are currently in the same basic orientation as the natural orientation
+                naturalOrientation = configOrientation;
+                break;
+            case Surface.ROTATION_90:
+            case Surface.ROTATION_270:
+                // We are currently in the other basic orientation to the natural orientation
+                naturalOrientation = (configOrientation == Configuration.ORIENTATION_LANDSCAPE) ?
+                        Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
+                break;
+        }
+
+        int[] orientationMap = {
+                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
+                ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
+                ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
+                ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
+        };
+        // Since the map starts at portrait, we need to offset if this device's natural orientation
+        // is landscape.
+        int indexOffset = 0;
+        if (naturalOrientation == Configuration.ORIENTATION_LANDSCAPE) {
+            indexOffset = 1;
+        }
+
+        // The map assumes default rotation. Check for reverse rotation and correct map if required
+        try {
+            if (getResources().getBoolean(getResources().getSystem().getIdentifier(
+                    "config_reverseDefaultRotation", "bool", "android"))) {
+                orientationMap[0] = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+                orientationMap[2] = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+            }
+        } catch (Resources.NotFoundException e) {
+            // If resource is not found, assume default rotation and continue
+            Log.d(TAG, "Cannot determine device rotation direction, assuming default");
+        }
+
+        setRequestedOrientation(orientationMap[(display.getRotation() + indexOffset) % 4]);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        // 6DoF is reset after a recreation of activity, which invalidates the tests.
+        if (mHasBeenPaused) {
+            Intent intent = this.getIntent();
+            intent.putExtra(EXTRA_RESULT_ID, ResultCode.FAILED_PAUSE_AND_RESUME);
+            this.setResult(RESULT_OK, intent);
+            finish();
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mHasBeenPaused = true;
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.menu_cts, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle action bar item clicks here.
+        int id = item.getItemId();
+
+        switch (id) {
+            case R.id.action_save_results:
+                saveResults();
+                return true;
+            case R.id.action_xml:
+                AlertDialog.Builder builder = new AlertDialog.Builder(this);
+
+                try {
+                    builder.setMessage(mDataFragment.getTestReport().getContents())
+                            .setTitle(R.string.results)
+                            .setPositiveButton(R.string.got_it, null);
+                } catch (IOException e) {
+                    Log.e(TAG, e.toString());
+                }
+
+                AlertDialog dialog = builder.create();
+                dialog.show();
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+    public void saveResults() {
+        try {
+            new ReportExporter(this, getTestReport().getContents()).execute();
+        } catch (IOException e) {
+            Log.e(TAG, "Couldn't create test report.");
+        }
+    }
+
+    public TestReport getTestReport() {
+        return mDataFragment.getTestReport();
+    }
+
+    public void listenFor6DofData(Fragment listener) {
+        mUiListener = (BaseUiListener) listener;
+        switch (mCurrentTest) {
+            case ACCURACY:
+                mAccuracyListener = (AccuracyListener) listener;
+                mRobustnessListener = null;
+                mComplexMovementListener = null;
+                break;
+            case ROBUSTNESS:
+                mAccuracyListener = null;
+                mRobustnessListener = (RobustnessListener) listener;
+                mComplexMovementListener = null;
+                break;
+            case COMPLEX_MOVEMENT:
+                mAccuracyListener = null;
+                mRobustnessListener = null;
+                mComplexMovementListener = (ComplexMovementListener) listener;
+                break;
+            default:
+                throw new AssertionError("mCurrentTest is a test that doesn't exist!");
+        }
+    }
+
+    public boolean isPoseProviderReady() {
+        if (mDataFragment != null) {
+            return mDataFragment.isPoseProviderReady();
+        } else {
+            return false;
+        }
+
+    }
+
+    public ArrayList<Waypoint> getUserGeneratedWaypoints(Lap lap) {
+        return mDataFragment.getUserGeneratedWaypoints(lap);
+    }
+
+    public Lap getLap() {
+        return mDataFragment.getLap();
+    }
+
+    public ArrayList<Ring> getRings() {
+        return mDataFragment.getRings();
+    }
+
+    @Override
+    public void onPoseProviderReady() {
+        if (mUiListener != null) {
+            mUiListener.onPoseProviderReady();
+        } else {
+            Log.e(TAG, getString(R.string.error_null_fragment));
+        }
+
+        // Possible for this to be called while switching UI fragments, so mUiListener is null
+        // but we want to start the test anyway.
+        mDataFragment.testStarted();
+    }
+
+    @Override
+    public void onWaypointPlaced() {
+        if (mUiListener != null) {
+            mUiListener.onWaypointPlaced();
+        } else {
+            Log.e(TAG, getString(R.string.error_null_fragment));
+        }
+    }
+
+    @Override
+    public void onResult(ResultObject result) {
+        if (mUiListener != null) {
+            mUiListener.onResult(result);
+        } else {
+            Log.e(TAG, getString(R.string.error_null_fragment));
+        }
+    }
+
+    @Override
+    public void onReset() {
+        if (mAccuracyListener != null) {
+            if (mCurrentTest == CTSTest.ACCURACY) {
+                mAccuracyListener.onReset();
+            } else {
+                throw new RuntimeException("We are in the wrong test for this listener to be called.");
+            }
+        } else {
+            Log.e(TAG, getString(R.string.error_null_fragment));
+        }
+    }
+
+    @Override
+    public void lap1Complete() {
+        if (mAccuracyListener != null) {
+            mAccuracyListener.lap1Complete();
+        } else {
+            Log.e(TAG, getString(R.string.error_null_fragment));
+        }
+    }
+
+    public void attemptWaypointPlacement() throws WaypointAreaCoveredException, WaypointDistanceException, WaypointStartPointException, WaypointRingNotEnteredException {
+        mDataFragment.onWaypointPlacementAttempt();
+    }
+
+    public void undoWaypointPlacement() {
+        if (mDataFragment != null) {
+            mDataFragment.undoWaypointPlacement();
+        } else {
+            Log.e(TAG, getString(R.string.error_retained_fragment_null));
+        }
+    }
+
+    public void readyForLap2() {
+        mDataFragment.startTest(CTSTest.ACCURACY);
+    }
+
+    public float getLatestDistanceData() {
+        return mDataFragment.getLatestDistanceData();
+    }
+
+    public float getTimeRemaining() {
+        return mDataFragment.getTimeRemaining();
+    }
+
+    public PoseProvider getPoseProvider() {
+        return mDataFragment.getPoseProvider();
+    }
+
+    @Override
+    public void onNewRotationData(RotationData data) {
+        if (mRobustnessListener != null) {
+            mRobustnessListener.onNewRotationData(data);
+        } else {
+            Log.e(TAG, getString(R.string.error_null_fragment));
+        }
+    }
+
+    @Override
+    public void onRingEntered(Ring ring) {
+        if (mComplexMovementListener != null) {
+            mComplexMovementListener.onRingEntered(ring);
+        } else {
+            Log.e(TAG, getString(R.string.error_null_fragment));
+        }
+    }
+
+    /**
+     * Loads test fragment for a particular phase.
+     *
+     * @param phase test to be started.
+     */
+    public void switchToTestFragment(CTSTest phase) {
+        Log.d(TAG, "switchToTestFragment");
+        Fragment fragment;
+
+        switch (phase) {
+            case ACCURACY:
+                fragment = AccuracyFragment.newInstance();
+                break;
+            case ROBUSTNESS:
+                fragment = RobustnessFragment.newInstance();
+                break;
+            case COMPLEX_MOVEMENT:
+                fragment = ComplexMovementFragment.newInstance(); //Complex Motion
+                break;
+            default:
+                throw new AssertionError("Trying to start a test that doesn't exist!");
+        }
+        FragmentManager fm = getFragmentManager();
+        FragmentTransaction transaction = fm.beginTransaction();
+        transaction.replace(R.id.contentFragment, fragment);
+        transaction.commit();
+    }
+
+    /**
+     * Loads start instruction fragment for a particular test.
+     *
+     * @param phase test to show instruction screen for.
+     */
+    public void switchToStartFragment(CTSTest phase) {
+        Log.e(TAG, "switchToStartFragment");
+        mUiListener = null;
+        mAccuracyListener = null;
+        mRobustnessListener = null;
+        mComplexMovementListener = null;
+
+        mCurrentTest = phase;
+        mDataFragment.startTest(mCurrentTest);
+        Fragment fragment = PhaseStartFragment.newInstance(phase);
+        FragmentManager fm = getFragmentManager();
+        FragmentTransaction transaction = fm.beginTransaction();
+        transaction.replace(R.id.contentFragment, fragment);
+        transaction.commit();
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        // We are always going to be restarting if this is called.
+        outState.putBoolean(EXTRA_ON_RESTART, true);
+        super.onSaveInstanceState(outState);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        onDestroyUi();
+        mUiListener = null;
+        mAccuracyListener = null;
+        mRobustnessListener = null;
+        mComplexMovementListener = null;
+        mDataFragment = null;
+    }
+
+    @Override
+    public void onDestroyUi() {
+        if (mUiListener != null) {
+            mUiListener.onDestroyUi();
+        }
+    }
+}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/BuildConfig.java
similarity index 82%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/BuildConfig.java
index 27a6fe2..dddbde7 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/BuildConfig.java
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package com.android.cts.verifier.sensors.sixdof;
 
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
+public class BuildConfig {
+    public static final boolean DEBUG = false;
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/AccuracyResultDialog.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/AccuracyResultDialog.java
new file mode 100644
index 0000000..1228c95
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/AccuracyResultDialog.java
@@ -0,0 +1,51 @@
+/*
+ * 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.verifier.sensors.sixdof.Dialogs;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.app.AlertDialog;
+import android.view.LayoutInflater;
+import android.widget.TextView;
+
+/**
+ * Dialog that displays the results of the first test.
+ */
+public class AccuracyResultDialog extends BaseResultsDialog {
+
+    public static AccuracyResultDialog newInstance(ResultObject resultObject) {
+        AccuracyResultDialog dialog = new AccuracyResultDialog();
+        dialog.setup(resultObject);
+        return dialog;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mBuilder = new AlertDialog.Builder(getActivity());
+        // Get the layout inflater.
+        LayoutInflater inflater = getActivity().getLayoutInflater();
+        mRootView = inflater.inflate(R.layout.dialog_result_accuracy, null);
+
+        mTextViews.put(ResultType.WAYPOINT, (TextView) mRootView.findViewById(R.id.tvWaypointResult));
+        mTextViews.put(ResultType.PATH, (TextView) mRootView.findViewById(R.id.tvPathResult));
+
+        // Parent class will actually create the dialog.
+        return super.onCreateDialog(savedInstanceState);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/BaseResultsDialog.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/BaseResultsDialog.java
new file mode 100644
index 0000000..1cb8aa2
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/BaseResultsDialog.java
@@ -0,0 +1,73 @@
+/*
+ * 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.verifier.sensors.sixdof.Dialogs;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.app.DialogFragment;
+import android.app.AlertDialog;
+import android.view.View;
+import android.widget.TextView;
+
+import java.util.HashMap;
+
+/**
+ * Class that sets up the displaying of test results in a dialog.
+ */
+public abstract class BaseResultsDialog extends DialogFragment {
+    public enum ResultType {
+        WAYPOINT,
+        PATH,
+        TIME,
+        ROTATION,
+        RINGS
+    }
+
+    protected ResultObject mResult;
+    protected HashMap<ResultType, TextView> mTextViews;
+    protected AlertDialog.Builder mBuilder;
+    protected View mRootView;
+
+    protected void setup(ResultObject result) {
+        mResult = result;
+        mTextViews = new HashMap<>();
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        // Please override and call super.onCreateDialog after setting up mRootView and mBuilder.
+        String title = getString(R.string.passed);
+        for (ResultType resultType : mResult.getResults().keySet()) {
+            if (mResult.getResults().get(resultType)) {
+                mTextViews.get(resultType).setText(getString(R.string.passed));
+            } else {
+                title = getString(R.string.failed);
+                mTextViews.get(resultType).setText(getString(R.string.failed));
+            }
+        }
+
+        mBuilder.setView(mRootView);
+
+        mBuilder.setTitle(title)
+                .setPositiveButton(R.string.got_it, null);
+
+        // Create the AlertDialog object and return it.
+        return mBuilder.create();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/ComplexMovementResultDialog.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/ComplexMovementResultDialog.java
new file mode 100644
index 0000000..cef2fde
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/ComplexMovementResultDialog.java
@@ -0,0 +1,51 @@
+/*
+ * 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.verifier.sensors.sixdof.Dialogs;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.app.AlertDialog;
+import android.view.LayoutInflater;
+import android.widget.TextView;
+
+/**
+ * Dialog that displays the results of the first test.
+ */
+public class ComplexMovementResultDialog extends BaseResultsDialog {
+
+    public static ComplexMovementResultDialog newInstance(ResultObject resultObject) {
+        ComplexMovementResultDialog dialog = new ComplexMovementResultDialog();
+        dialog.setup(resultObject);
+        return dialog;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mBuilder = new AlertDialog.Builder(getActivity());
+        // Get the layout inflater.
+        LayoutInflater inflater = getActivity().getLayoutInflater();
+        mRootView = inflater.inflate(R.layout.dialog_result_complex_movement, null);
+
+        mTextViews.put(ResultType.WAYPOINT, (TextView) mRootView.findViewById(R.id.tvWaypointResult));
+        mTextViews.put(ResultType.RINGS, (TextView) mRootView.findViewById(R.id.tvRingsResult));
+
+        // Create the AlertDialog object and return it.
+        return super.onCreateDialog(savedInstanceState);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/Lap2Dialog.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/Lap2Dialog.java
new file mode 100644
index 0000000..a38d11b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/Lap2Dialog.java
@@ -0,0 +1,74 @@
+/*
+ * 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.verifier.sensors.sixdof.Dialogs;
+
+import com.android.cts.verifier.R;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.app.DialogFragment;
+import android.app.AlertDialog;
+
+/**
+ * Dialog for instructions on what to to on lap 2
+ */
+public class Lap2Dialog extends DialogFragment {
+    Lap2DialogListener mListener;
+
+    public static Lap2Dialog newInstance() {
+        Lap2Dialog dialog = new Lap2Dialog();
+        return dialog;
+    }
+
+    public interface Lap2DialogListener {
+        void onLap2Start();
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        // Use the Builder class for convenient dialog construction.
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+        // Inflate and set the layout for the dialog.
+        // Pass null as the parent view because its going in the dialog layout.
+        builder.setTitle(R.string.test1_pass2)
+                .setMessage(R.string.lap2_instructions)
+                .setNegativeButton(R.string.got_it, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        mListener.onLap2Start();
+                    }
+                });
+
+        // Create the AlertDialog object and return it.
+        return builder.create();
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        // Verify that the host fragment implements the callback interface.
+        try {
+            mListener = (Lap2DialogListener) getTargetFragment();
+            mListener.onLap2Start();
+        } catch (ClassCastException e) {
+            // The activity doesn't implement the interface, throw exception.
+            throw new ClassCastException(activity.toString()
+                    + " must implement Lap2DialogListener");
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/RobustnessResultDialog.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/RobustnessResultDialog.java
new file mode 100644
index 0000000..522c7c1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Dialogs/RobustnessResultDialog.java
@@ -0,0 +1,52 @@
+/*
+ * 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.verifier.sensors.sixdof.Dialogs;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.app.AlertDialog;
+import android.view.LayoutInflater;
+import android.widget.TextView;
+
+/**
+ * Dialog that displays the results of the first test.
+ */
+public class RobustnessResultDialog extends BaseResultsDialog {
+
+    public static RobustnessResultDialog newInstance(ResultObject resultObject) {
+        RobustnessResultDialog dialog = new RobustnessResultDialog();
+        dialog.setup(resultObject);
+        return dialog;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mBuilder = new AlertDialog.Builder(getActivity());
+        // Get the layout inflater.
+        LayoutInflater inflater = getActivity().getLayoutInflater();
+        mRootView = inflater.inflate(R.layout.dialog_result_robustness, null);
+
+        mTextViews.put(ResultType.WAYPOINT, (TextView) mRootView.findViewById(R.id.tvWaypointResult));
+        mTextViews.put(ResultType.PATH, (TextView) mRootView.findViewById(R.id.tvPathResult));
+        mTextViews.put(ResultType.TIME, (TextView) mRootView.findViewById(R.id.tvTimeResult));
+        mTextViews.put(ResultType.ROTATION, (TextView) mRootView.findViewById(R.id.tvRotationResult));
+
+        return super.onCreateDialog(savedInstanceState);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/AccuracyFragment.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/AccuracyFragment.java
new file mode 100644
index 0000000..64c44c7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/AccuracyFragment.java
@@ -0,0 +1,303 @@
+/*
+ * 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.verifier.sensors.sixdof.Fragments;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.BuildConfig;
+import com.android.cts.verifier.sensors.sixdof.Activities.TestActivity;
+import com.android.cts.verifier.sensors.sixdof.Dialogs.AccuracyResultDialog;
+import com.android.cts.verifier.sensors.sixdof.Dialogs.Lap2Dialog;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.AccuracyListener;
+import com.android.cts.verifier.sensors.sixdof.Renderer.AccuracyRenderer;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+
+import android.app.Activity;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.app.DialogFragment;
+import android.app.AlertDialog;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+
+/**
+ * UI fragment for the first test.
+ */
+public class AccuracyFragment extends BaseUiFragment implements AccuracyListener,
+        Lap2Dialog.Lap2DialogListener {
+    private static final String TAG = "AccuracyFragment";
+
+    private String mCurrentObjective = "";
+
+    private TextView mTvDistanceRemaining;
+    private TextView mTvMarkers;
+    private TextView mTvObjective;
+
+    /**
+     * Necessary empty constructor.
+     */
+    public AccuracyFragment() {
+    }
+
+    /**
+     * Standard practice to have a static newInstance constructor. Used to pass in arguments to the
+     * fragment. We don't have any at the moment, but this is good structure for the future.
+     *
+     * @return a new Accuracy test fragment.
+     */
+    public static AccuracyFragment newInstance() {
+        AccuracyFragment fragment = new AccuracyFragment();
+        return fragment;
+    }
+
+    /**
+     * Called when the parent activity has been created. Adds the GLSurfaceView to the fragment
+     * layout.
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        GLSurfaceView surfaceView = new GLSurfaceView(getActivity());
+        surfaceView.setEGLContextClientVersion(2);
+        mRenderer = new AccuracyRenderer(getActivity());
+        surfaceView.setRenderer(mRenderer);
+        mLLCameraLayout = (LinearLayout) getView().findViewById(R.id.llCamera);
+        mLLCameraLayout.addView(surfaceView);
+        Log.d(TAG, "Camera Preview add to layout");
+    }
+
+    /**
+     * Initialises all of the UI elements
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.fragment_accuracy, container, false);
+        getActivity().setTitle(getResources().getStringArray(R.array.phase)[TestActivity.CTSTest.ACCURACY.ordinal()]);
+        mTvDistanceRemaining = (TextView) view.findViewById(R.id.tvTranslations);
+        mTvMarkers = (TextView) view.findViewById(R.id.tvMarkers);
+        mTvObjective = (TextView) view.findViewById(R.id.tvObjective);
+        mPlaceWaypointButton = (ImageButton) view.findViewById(R.id.fabPlaceWaypoint);
+        mPlaceWaypointButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    mActivity.attemptWaypointPlacement();
+                } catch (WaypointDistanceException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_distance), Toast.LENGTH_SHORT).show();
+                } catch (WaypointAreaCoveredException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_area), Toast.LENGTH_SHORT).show();
+                } catch (WaypointStartPointException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_start_point), Toast.LENGTH_SHORT).show();
+                } catch (WaypointRingNotEnteredException e) {
+                    throw new AssertionError(
+                            "WaypointRingNotEnteredException when not in 3rd test", e);
+                }
+            }
+        });
+
+        // Setup buttons for pass/info/fail
+        setupButtons(view, TestActivity.CTSTest.ACCURACY);
+
+        return view;
+    }
+
+    /**
+     * Called after onCreateView. Starts listening for 6DoF events.
+     */
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        mActivity.listenFor6DofData(this);
+    }
+
+    @Override
+    protected void setupUILoop() {
+        Runnable runnable = new Runnable() {
+
+            @Override
+            public void run() {
+                DecimalFormat oneDecimalFormat = new DecimalFormat("0.0");
+
+                if (mActivity == null || getActivity() == null) {
+                    return;
+                }
+
+                String distanceString = "";
+                String markerString = "";
+                ArrayList<Waypoint> referenceWaypoints;
+
+                switch (mActivity.getLap()) {
+                    case LAP_1:
+                        referenceWaypoints = mActivity.getUserGeneratedWaypoints(Manager.Lap.LAP_1);
+
+                        float distanceRemaining = 0f;
+
+                        if (referenceWaypoints.size() > 0) {
+                            distanceRemaining = mActivity.getLatestDistanceData();
+                            float adjustedDistanceRemaining = Math.max(distanceRemaining, 0);
+                            distanceString = getResources().getString(R.string.distance_remaining) +
+                                    oneDecimalFormat.format(adjustedDistanceRemaining);
+
+                            markerString = getResources().getString(R.string.markers);
+                            for (Waypoint waypoint : referenceWaypoints) {
+                                markerString +=
+                                        MathsUtils.coordinatesToString(waypoint.getCoordinates()) + "\n";
+                            }
+                        }
+
+                        if (distanceRemaining <= 0 || referenceWaypoints.size() == 0) {
+                            mPlaceWaypointButton.setVisibility(View.VISIBLE);
+                        } else {
+                            mPlaceWaypointButton.setVisibility(View.INVISIBLE);
+                        }
+                        break;
+                    case LAP_2:
+                        referenceWaypoints = mActivity.getUserGeneratedWaypoints(Manager.Lap.LAP_2);
+
+                        if (referenceWaypoints.size() == Manager.MAX_MARKER_NUMBER) {
+                            mPlaceWaypointButton.setVisibility(View.INVISIBLE);
+                        } else {
+                            mPlaceWaypointButton.setVisibility(View.VISIBLE);
+                        }
+                        break;
+                    default:
+                        //Possible for this state to be entered when switching fragments
+                        Log.e(TAG, "Trying to run UI on Accuracy Test on a lap greater than 2");
+
+                        //Use an empty list as not interested in this state
+                        referenceWaypoints = new ArrayList<Waypoint>();
+                }
+
+                mCurrentObjective = getObjectiveText(mActivity.getLap(), referenceWaypoints.size());
+
+                mTvDistanceRemaining.setText(distanceString);
+                mTvMarkers.setText(markerString);
+                mTvObjective.setText(mCurrentObjective);
+
+                //Update the UI again in x milliseconds.
+                if (mHandler != null) {
+                    mHandler.postDelayed(this, UI_UPDATE_DELAY);
+                }
+            }
+        };
+
+        super.initUIHandler(runnable);
+    }
+
+    /**
+     * Called when this phase is done and a result is ready. Shows the results dialog and enables
+     * pass button if test has been passed.
+     */
+    @Override
+    public void onResult(ResultObject result) {
+        AccuracyResultDialog dialog = AccuracyResultDialog.newInstance(result);
+        dialog.setTargetFragment(AccuracyFragment.this, DIALOG_FRAGMENT);
+        dialog.show(getActivity().getFragmentManager(), "ResultDialogFragment");
+        mPlaceWaypointButton.setVisibility(View.INVISIBLE);
+
+        if (result.hasPassed() || BuildConfig.DEBUG) {
+            mBtnPass.setEnabled(true);
+            mBtnPass.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View view) {
+                    onReadyForPhase2();
+                }
+            });
+        }
+    }
+
+    /**
+     * Resets UI to how it is at the start of test. Currently called when first waypoint is undone.
+     */
+    @Override
+    public void onReset() {
+        mActivity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mPlaceWaypointButton.setVisibility(View.VISIBLE);
+                mTvDistanceRemaining.setText("");
+                mTvMarkers.setText("");
+                mCurrentObjective = getResources().getStringArray(R.array.initial_waypoint)[0];
+                mTvObjective.setText(mCurrentObjective);
+            }
+        });
+    }
+
+    @Override
+    public void lap1Complete() {
+        onBackToFirstWaypoint();
+        mActivity.readyForLap2();
+    }
+
+    /**
+     * Shows initial instruction dialog
+     */
+    @Override
+    protected void showInitialDialog() {
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+        builder.setMessage(R.string.phase1_initial_message)
+                .setTitle(R.string.initial)
+                .setPositiveButton(R.string.got_it, null);
+
+        AlertDialog dialog = builder.create();
+        dialog.show();
+    }
+
+    /**
+     * Called when user finishes the first lap
+     */
+    public void onBackToFirstWaypoint() {
+        DialogFragment dialog = Lap2Dialog.newInstance();
+        dialog.setTargetFragment(AccuracyFragment.this, DIALOG_FRAGMENT);
+        dialog.show(getActivity().getFragmentManager(), "Lap2DialogFragment");
+    }
+
+    /**
+     * Move to next test
+     */
+    public void onReadyForPhase2() {
+        mActivity.switchToStartFragment(TestActivity.CTSTest.ROBUSTNESS);
+    }
+
+    /**
+     * Called when lap 2 starts.
+     */
+    @Override
+    public void onLap2Start() {
+        mPlaceWaypointButton.setVisibility(View.VISIBLE);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/BaseUiFragment.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/BaseUiFragment.java
new file mode 100644
index 0000000..12f0652
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/BaseUiFragment.java
@@ -0,0 +1,198 @@
+/*
+ * 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.verifier.sensors.sixdof.Fragments;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.Activities.StartActivity;
+import com.android.cts.verifier.sensors.sixdof.Activities.TestActivity;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.BaseUiListener;
+import com.android.cts.verifier.sensors.sixdof.Renderer.BaseRenderer;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Handler;
+import android.app.Fragment;
+import android.app.AlertDialog;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+
+import java.io.IOException;
+
+/**
+ * Abstract class that UI Fragments for each test inherit from,
+ */
+public abstract class BaseUiFragment extends Fragment implements BaseUiListener {
+    private static final String TAG = "BaseUiFragment";
+    protected static final long UI_UPDATE_DELAY = 200;
+
+    protected static final int DIALOG_FRAGMENT = 1;
+
+    protected Button mBtnPass;
+    protected Button mBtnInfo;
+    protected Button mBtnFail;
+    protected ImageButton mPlaceWaypointButton;
+
+    protected LinearLayout mLLCameraLayout;
+
+    protected TestActivity mActivity;
+
+    protected Handler mHandler;
+    protected Runnable mUIUpdateRunnable;
+
+    protected BaseRenderer mRenderer;
+
+    /**
+     * Called when this fragment is attached to an activity. Starts the test if the Pose service is
+     * ready.
+     */
+    @Override
+    public void onAttach(Activity context) {
+        super.onAttach(context);
+        mActivity = (TestActivity) getActivity();
+
+        if (mActivity.isPoseProviderReady()) {
+            onPoseProviderReady();
+        }
+    }
+
+    protected void initUIHandler(Runnable uiRunnable) {
+        mHandler = new Handler();
+        mUIUpdateRunnable = uiRunnable;
+        mHandler.postDelayed(mUIUpdateRunnable, UI_UPDATE_DELAY);
+    }
+
+    protected void setupButtons(View fragmentView, TestActivity.CTSTest currentPhase) {
+        final int phaseIndex = currentPhase.ordinal();
+        mBtnPass = (Button) fragmentView.findViewById(R.id.btnPass);
+        mBtnInfo = (Button) fragmentView.findViewById(R.id.btnInfo);
+        mBtnFail = (Button) fragmentView.findViewById(R.id.btnFail);
+
+        mBtnInfo.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+                builder.setMessage(getResources().getStringArray(R.array.phase_descriptions)[phaseIndex])
+                        .setTitle(getResources().getStringArray(R.array.phase)[phaseIndex])
+                        .setPositiveButton(R.string.got_it, null);
+
+                AlertDialog dialog = builder.create();
+                dialog.show();
+            }
+        });
+
+        mBtnFail.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                Intent resultIntent = getActivity().getIntent();
+                String report = "Couldn't create test report.";
+                try {
+                    report = mActivity.getTestReport().getContents();
+                } catch (IOException e) {
+                    Log.e(TAG, report);
+                }
+                resultIntent.putExtra(TestActivity.EXTRA_REPORT, report);
+                resultIntent.putExtra(TestActivity.EXTRA_RESULT_ID, StartActivity.ResultCode.FAILED);
+                getActivity().setResult(Activity.RESULT_OK, resultIntent);
+                getActivity().finish();
+            }
+        });
+    }
+
+    protected abstract void setupUILoop();
+
+    protected abstract void showInitialDialog();
+
+    protected String getObjectiveText(Manager.Lap lap, int waypointCount) {
+        String currentObjective = "";
+        int lapIndex = lap.ordinal();
+        if (lapIndex > 1) lapIndex = 1; // Text is same for indexes 1, 2, 3
+
+        switch (waypointCount) {
+            case 0:
+                currentObjective = getResources()
+                        .getStringArray(R.array.initial_waypoint)[lapIndex];
+                break;
+            case Manager.MAX_MARKER_NUMBER - 1:
+                currentObjective = getString(R.string.obj_return_to_initial_waypoint);
+                break;
+            case Manager.MAX_MARKER_NUMBER:
+                currentObjective = "";
+                mPlaceWaypointButton.setVisibility(View.INVISIBLE);
+                break;
+            default:
+                currentObjective = getResources()
+                        .getStringArray(R.array.next_waypoint)[lapIndex]
+                        .replace('0', Character.forDigit(waypointCount, 10));
+                break;
+        }
+
+        return currentObjective;
+    }
+
+    /**
+     * Nullify activity to avoid memory leak.
+     */
+    @Override
+    public void onDetach() {
+        super.onDetach();
+
+        mActivity = null;
+        mHandler = null;
+        mUIUpdateRunnable = null;
+    }
+
+    @Override
+    public void onDestroyUi() {
+        if (mRenderer != null) {
+            mRenderer.onDestroy();
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (mRenderer != null) {
+            mRenderer.disconnectCamera();
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        if (mRenderer != null) {
+            mRenderer.connectCamera(mActivity.getPoseProvider(), getActivity());
+        }
+    }
+
+    @Override
+    public void onPoseProviderReady() {
+        showInitialDialog();
+        setupUILoop();
+    }
+
+    /**
+     * Called when a waypoint has been successfully placed by user. Shows undo snackbar.
+     */
+    @Override
+    public void onWaypointPlaced() {
+        mPlaceWaypointButton.setVisibility(View.INVISIBLE);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/ComplexMovementFragment.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/ComplexMovementFragment.java
new file mode 100644
index 0000000..d919075
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/ComplexMovementFragment.java
@@ -0,0 +1,228 @@
+/*
+ * 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.verifier.sensors.sixdof.Fragments;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.BuildConfig;
+import com.android.cts.verifier.sensors.sixdof.Activities.StartActivity;
+import com.android.cts.verifier.sensors.sixdof.Activities.TestActivity;
+import com.android.cts.verifier.sensors.sixdof.Dialogs.ComplexMovementResultDialog;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.ComplexMovementListener;
+import com.android.cts.verifier.sensors.sixdof.Renderer.ComplexMovementRenderer;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.ComplexMovementPath;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.app.AlertDialog;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.IOException;
+
+/**
+ * UI fragment for the third test.
+ */
+public class ComplexMovementFragment extends BaseUiFragment implements ComplexMovementListener {
+    private static final String TAG = "ComplexMovementFragment";
+
+    private TextView mTvObjective;
+    private TextView mTvRings;
+
+    /**
+     * Standard practice to have a static newInstance constructor. Used to pass in arguments to the
+     * fragment. We don't have any at the moment, but this is good structure for the future.
+     *
+     * @return a new Robustness test fragment.
+     */
+    public static ComplexMovementFragment newInstance() {
+        return new ComplexMovementFragment();
+    }
+
+    /**
+     * Called when the parent activity has been created. Adds the GLSurfaceView to the fragment
+     * layout.
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        GLSurfaceView surfaceView = new GLSurfaceView(getActivity());
+        surfaceView.setEGLContextClientVersion(2);
+        mRenderer = new ComplexMovementRenderer(getActivity(), mActivity.getRings());
+        surfaceView.setRenderer(mRenderer);
+        mLLCameraLayout = (LinearLayout) getView().findViewById(R.id.llCamera);
+        mLLCameraLayout.addView(surfaceView);
+        Log.d(TAG, "Camera Preview add to layout");
+    }
+
+    /**
+     * Initialises all of the UI elements
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.fragment_complex_movement, container, false);
+        getActivity().setTitle(getResources().getStringArray(R.array.phase)[TestActivity.CTSTest.COMPLEX_MOVEMENT.ordinal()]);
+
+        // Set up pass/info/fail buttons.
+        setupButtons(view, TestActivity.CTSTest.COMPLEX_MOVEMENT);
+
+        mPlaceWaypointButton = (ImageButton) view.findViewById(R.id.fabPlaceWaypoint);
+        mPlaceWaypointButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    mActivity.attemptWaypointPlacement();
+                } catch (WaypointAreaCoveredException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_area), Toast.LENGTH_SHORT).show();
+                } catch (WaypointDistanceException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_distance), Toast.LENGTH_SHORT).show();
+                } catch (WaypointStartPointException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_start_point), Toast.LENGTH_SHORT).show();
+                } catch (WaypointRingNotEnteredException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_rings_not_entered), Toast.LENGTH_SHORT).show();
+                }
+            }
+        });
+
+        mTvObjective = (TextView) view.findViewById(R.id.tvObjective);
+        mTvRings = (TextView) view.findViewById(R.id.tvRings);
+
+        return view;
+    }
+
+    /**
+     * Called after onCreateView. Starts listening for 6DoF events.
+     */
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        mActivity.listenFor6DofData(this);
+    }
+
+    @Override
+    protected void setupUILoop() {
+        Runnable runnable = new Runnable() {
+            @Override
+            public void run() {
+                if (mActivity == null || getActivity() == null) {
+                    return;
+                }
+
+                int waypointCount = mActivity.getUserGeneratedWaypoints(Manager.Lap.LAP_4).size();
+                mTvObjective.setText(getObjectiveText(Manager.Lap.LAP_4, waypointCount));
+
+                int ringCount = 0;
+                for (Ring ring : mActivity.getRings()) {
+                    if (ring.getPathNumber() == waypointCount && ring.isEntered()) {
+                        ringCount++;
+                    }
+                }
+
+                mTvRings.setText(String.format(getString(R.string.rings_entered),
+                        ringCount, ComplexMovementPath.RINGS_PER_PATH));
+
+                if (waypointCount < Manager.MAX_MARKER_NUMBER) {
+                    mPlaceWaypointButton.setVisibility(View.VISIBLE);
+                }
+
+                // Update the UI again in x milliseconds.
+                if (mHandler != null) {
+                    mHandler.postDelayed(this, UI_UPDATE_DELAY);
+                }
+            }
+        };
+
+        super.initUIHandler(runnable);
+    }
+
+    /**
+     * Shows initial instruction dialog
+     */
+    @Override
+    protected void showInitialDialog() {
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+        builder.setMessage(R.string.phase3_initial_message)
+                .setTitle(getResources().getStringArray(R.array.phase)[TestActivity.CTSTest.COMPLEX_MOVEMENT.ordinal()])
+                .setPositiveButton(R.string.got_it, null);
+
+        AlertDialog dialog = builder.create();
+        dialog.show();
+    }
+
+    @Override
+    public void onWaypointPlaced() {
+        super.onWaypointPlaced();
+        ((ComplexMovementRenderer) mRenderer).onWaypointPlaced(mActivity.getUserGeneratedWaypoints(Manager.Lap.LAP_4).size());
+    }
+
+    @Override
+    public void onRingEntered(Ring ring) {
+        ((ComplexMovementRenderer) mRenderer).onRingEntered(ring);
+    }
+
+    @Override
+    public void onResult(ResultObject result) {
+        ComplexMovementResultDialog dialog = ComplexMovementResultDialog.newInstance(result);
+        dialog.setTargetFragment(ComplexMovementFragment.this, DIALOG_FRAGMENT);
+        dialog.show(getActivity().getFragmentManager(), "ResultDialogFragment");
+        mPlaceWaypointButton.setVisibility(View.INVISIBLE);
+
+        if (result.hasPassed() || BuildConfig.DEBUG) {
+            mBtnPass.setEnabled(true);
+            mBtnPass.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View view) {
+                    finishTest();
+                }
+            });
+        }
+    }
+
+    private void finishTest() {
+        Intent resultIntent = getActivity().getIntent();
+        String report = "Couldn't create test report.";
+        try {
+            report = mActivity.getTestReport().getContents();
+        } catch (IOException e) {
+            Log.e(TAG, report);
+        }
+        resultIntent.putExtra(TestActivity.EXTRA_REPORT, report);
+        resultIntent.putExtra(TestActivity.EXTRA_RESULT_ID, StartActivity.ResultCode.PASSED);
+        getActivity().setResult(Activity.RESULT_OK, resultIntent);
+        getActivity().finish();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/DataFragment.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/DataFragment.java
new file mode 100644
index 0000000..baa01f6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/DataFragment.java
@@ -0,0 +1,221 @@
+/*
+ * 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.verifier.sensors.sixdof.Fragments;
+
+
+import com.android.cts.verifier.sensors.sixdof.Activities.TestActivity;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.TestReport;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint;
+import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.AndroidPoseProvider;
+import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.PoseData;
+import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.PoseProvider;
+
+import android.app.Activity;
+import android.content.Context;
+import android.app.Fragment;
+
+import java.util.ArrayList;
+
+/**
+ * This currently deals with the pose data and what to do with it.
+ */
+public class DataFragment extends Fragment implements PoseProvider.PoseProviderListener {
+    private final static String TAG = "DataFragment";
+
+    private TestReport mTestReport;
+    private Manager mManager;
+
+    private PoseProvider mPoseProvider;
+    protected boolean mIsPoseProviderReady = false;
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mPoseProvider = new AndroidPoseProvider(getActivity(), this);
+        mPoseProvider.setup();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mPoseProvider = null;
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mPoseProvider.onStopPoseProviding();
+        mIsPoseProviderReady = false;
+    }
+
+    /**
+     * Start PoseProvider.
+     */
+    @Override
+    public void onSetupComplete() {
+        mPoseProvider.onStartPoseProviding();
+    }
+
+    @Override
+    public void onNewPoseData(PoseData newPoseData) {
+        if (!mIsPoseProviderReady) {
+            mIsPoseProviderReady = true;
+            mManager.onPoseProviderReady();
+        }
+
+        mManager.onNewPoseData(newPoseData);
+    }
+
+    /**
+     * Assign the listener when this fragment is attached to an activity.
+     *
+     * @param activity the activity that this fragment is attached to.
+     */
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        initManager(activity);
+    }
+
+    private void initManager(Context context) {
+        mTestReport = new TestReport(getActivity());
+        mManager = new Manager(mTestReport);
+        mManager.setupListeners(context);
+    }
+
+    /**
+     * Nullify the listener to avoid leaking the activity.
+     */
+    @Override
+    public void onDetach() {
+        super.onDetach();
+        mManager.stopListening();
+    }
+
+    /**
+     * @return PoseProvider object associated with these tests.
+     */
+    public PoseProvider getPoseProvider() {
+        return mPoseProvider;
+    }
+
+    /**
+     * @return true if we are connected to the pose provider.
+     */
+    public boolean isPoseProviderReady() {
+        return mIsPoseProviderReady;
+    }
+
+    /**
+     * Gets all the markers (user generated waypoints) for the specified phase.
+     *
+     * @param lap the lap of the test to get the markers from
+     * @return a list of the markers
+     */
+    public ArrayList<Waypoint> getUserGeneratedWaypoints(Manager.Lap lap) {
+        switch (lap) {
+            case LAP_1:
+                return mManager.getReferencePathMarkers();
+            case LAP_2:
+                return mManager.getTestPathMarkers();
+            case LAP_3:
+                return mManager.getRobustnessMarker();
+            case LAP_4:
+                return mManager.getComplexMovementTestMarkers();
+            default:
+                throw new AssertionError("Unrecognised Lap!", null);
+        }
+    }
+
+    /**
+     * Returns a reference to the mTestReport object.
+     */
+    public TestReport getTestReport() {
+        return mTestReport;
+    }
+
+    /**
+     * Initiates the adding of a waypoint and checks if the state of the current test need to be
+     * changed.
+     *
+     * @throws WaypointDistanceException    if the location is too close to another
+     * @throws WaypointAreaCoveredException if the area covered by the user is too little
+     * @throws WaypointStartPointException  if the location is not close enough to the start
+     */
+    public void onWaypointPlacementAttempt()
+            throws WaypointStartPointException, WaypointDistanceException,
+            WaypointAreaCoveredException, WaypointRingNotEnteredException {
+        synchronized (TestActivity.POSE_LOCK) {
+            mManager.addPoseDataToPath(
+                    mPoseProvider.getLatestPoseData().getTranslationAsFloats(), true);
+        }
+    }
+
+    /**
+     * Removes the last marker added in the current test phase.
+     */
+    public void undoWaypointPlacement() {
+        mManager.removeLastAddedMarker();
+    }
+
+    /**
+     * Returns the current phase of the test.
+     */
+    public Manager.Lap getLap() {
+        return mManager.getLap();
+    }
+
+    /**
+     * Sets the test status to executed.
+     */
+    public void testStarted() {
+        mTestReport.setTestState(TestReport.TestStatus.EXECUTED);
+    }
+
+    public void startTest(TestActivity.CTSTest newTest) {
+        switch (newTest) {
+            case ACCURACY:
+                mManager.startAccuracyTest();
+                break;
+            case ROBUSTNESS:
+                mManager.startRobustnessTest();
+                break;
+            case COMPLEX_MOVEMENT:
+                mManager.startComplexMovementTest();
+                break;
+            default:
+                throw new AssertionError("Test not recognised!");
+        }
+    }
+
+    public float getLatestDistanceData() {
+        return mManager.getRemainingPath();
+    }
+
+    public float getTimeRemaining() {
+        return mManager.getTimeRemaining();
+    }
+
+    public ArrayList<Ring> getRings() {
+        return mManager.getRings();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/PhaseStartFragment.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/PhaseStartFragment.java
new file mode 100644
index 0000000..2013c12
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/PhaseStartFragment.java
@@ -0,0 +1,86 @@
+/*
+ * 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.verifier.sensors.sixdof.Fragments;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.Activities.TestActivity;
+
+import android.os.Bundle;
+import android.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Provides the instructions for a particular phase before it starts.
+ */
+public class PhaseStartFragment extends Fragment {
+    // Identifier for setting and retrieving the phase this Fragment was designed for.
+    private static final String ARG_PHASE = "ArgPhase";
+
+    Button mBtnStart;
+    TextView mTvDesc;
+
+    TestActivity.CTSTest mPhase;
+    TestActivity mActivity;
+
+    public static PhaseStartFragment newInstance(TestActivity.CTSTest phase) {
+        PhaseStartFragment fragment = new PhaseStartFragment();
+        Bundle arguments = new Bundle();
+        arguments.putSerializable(ARG_PHASE, phase);
+        fragment.setArguments(arguments);
+
+        return fragment;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        View rootView = inflater.inflate(R.layout.fragment_start_phase, container, false);
+        mBtnStart = (Button) rootView.findViewById(R.id.btnStart);
+        mTvDesc = (TextView) rootView.findViewById(R.id.tvDesc);
+        mActivity = (TestActivity) getActivity();
+
+        mPhase = (TestActivity.CTSTest) getArguments().getSerializable(ARG_PHASE);
+
+        switch (mPhase) {
+            case ACCURACY:
+                mTvDesc.setText(getString(R.string.phase1_description));
+                getActivity().setTitle(getResources().getStringArray(R.array.phase)[TestActivity.CTSTest.ACCURACY.ordinal()]);
+                break;
+            case ROBUSTNESS:
+                mTvDesc.setText(getString(R.string.phase2_description));
+                getActivity().setTitle(getResources().getStringArray(R.array.phase)[TestActivity.CTSTest.ROBUSTNESS.ordinal()]);
+                break;
+            case COMPLEX_MOVEMENT:
+                mTvDesc.setText(getString(R.string.phase3_description));
+                getActivity().setTitle(getResources().getStringArray(R.array.phase)[TestActivity.CTSTest.COMPLEX_MOVEMENT.ordinal()]);
+                break;
+            default:
+                throw new AssertionError("Trying to start a test that doesn't exist");
+        }
+
+        mBtnStart.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                mActivity.switchToTestFragment(mPhase);
+            }
+        });
+
+        return rootView;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/RobustnessFragment.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/RobustnessFragment.java
new file mode 100644
index 0000000..f7b089b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Fragments/RobustnessFragment.java
@@ -0,0 +1,243 @@
+/*
+ * 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.verifier.sensors.sixdof.Fragments;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.BuildConfig;
+import com.android.cts.verifier.sensors.sixdof.Activities.TestActivity;
+import com.android.cts.verifier.sensors.sixdof.Dialogs.RobustnessResultDialog;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.RobustnessListener;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RobustnessRenderer;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.Colour;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.RotationData;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+
+import android.app.Activity;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.app.AlertDialog;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * UI fragment for the second test.
+ */
+public class RobustnessFragment extends BaseUiFragment implements RobustnessListener {
+    private static final String TAG = "RobustnessFragment";
+    private static final Object TIMER_LOCK = new Object();
+
+    private TextView mTvTime;
+    private TextView mTvPassColour;
+    private TextView mTvObjective;
+
+    private boolean mIsPassing = false;
+    private boolean mResultGiven = false;
+
+    /**
+     * Standard practice to have a static newInstance constructor. Used to pass in arguments to the
+     * fragment. We don't have any at the moment, but this is good structure for the future.
+     *
+     * @return a new Robustness test fragment.
+     */
+    public static RobustnessFragment newInstance() {
+        RobustnessFragment fragment = new RobustnessFragment();
+        return fragment;
+    }
+
+    /**
+     * Called when the parent activity has been created. Adds the GLSurfaceView to the fragment
+     * layout.
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        GLSurfaceView surfaceView = new GLSurfaceView(getActivity());
+        surfaceView.setEGLContextClientVersion(2);
+        mRenderer = new RobustnessRenderer(getActivity());
+        surfaceView.setRenderer(mRenderer);
+        mLLCameraLayout = (LinearLayout) getView().findViewById(R.id.llCamera);
+        mLLCameraLayout.addView(surfaceView);
+        Log.d(TAG, "Camera Preview add to layout");
+    }
+
+    /**
+     * Initialises all of the UI elements.
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.fragment_robustness, container, false);
+        getActivity().setTitle(getResources().getStringArray(R.array.phase)[TestActivity.CTSTest.ROBUSTNESS.ordinal()]);
+
+        // Set up pass/info/fail buttons
+        setupButtons(view, TestActivity.CTSTest.ROBUSTNESS);
+
+        mPlaceWaypointButton = (ImageButton) view.findViewById(R.id.fabPlaceWaypoint);
+        mPlaceWaypointButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    mActivity.attemptWaypointPlacement();
+                } catch (WaypointDistanceException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_distance), Toast.LENGTH_SHORT).show();
+                } catch (WaypointAreaCoveredException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_area), Toast.LENGTH_SHORT).show();
+                } catch (WaypointStartPointException e) {
+                    Toast.makeText(getActivity(),
+                            getString(R.string.error_start_point), Toast.LENGTH_SHORT).show();
+                } catch (WaypointRingNotEnteredException e) {
+                    throw new AssertionError(
+                            "WaypointRingNotEnteredException when not in 3rd test", e);
+                }
+            }
+        });
+
+        mTvTime = (TextView) view.findViewById(R.id.tvTimer);
+        mTvPassColour = (TextView) view.findViewById(R.id.tvPassColour);
+        mTvObjective = (TextView) view.findViewById(R.id.tvObjective);
+
+        return view;
+    }
+
+    /**
+     * Called after onCreateView. Starts listening for 6DoF events.
+     */
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        mActivity.listenFor6DofData(this);
+    }
+
+    @Override
+    protected void setupUILoop() {
+        Runnable runnable = new Runnable() {
+            @Override
+            public void run() {
+                if (mActivity == null || getActivity() == null) {
+                    return;
+                }
+
+                String stringTimeRemaining;
+                String decimalTimeRemaining = (mActivity.getTimeRemaining() / 1000f) + "";
+                synchronized (TIMER_LOCK) {
+                    stringTimeRemaining = String.format(getString(R.string.time_remaining), decimalTimeRemaining);
+                }
+
+                synchronized (TIMER_LOCK) {
+                    if (mIsPassing) {
+                        mTvPassColour.setBackgroundColor(getResources().getColor(R.color.green));
+                    } else {
+                        mTvPassColour.setBackgroundColor(getResources().getColor(R.color.red));
+                    }
+                }
+
+                int waypointCount = mActivity.getUserGeneratedWaypoints(Manager.Lap.LAP_3).size();
+                mTvObjective.setText(getObjectiveText(Manager.Lap.LAP_3, waypointCount));
+
+                if (waypointCount < Manager.MAX_MARKER_NUMBER && !mResultGiven) {
+                    mPlaceWaypointButton.setVisibility(View.VISIBLE);
+                    mTvTime.setText(stringTimeRemaining);
+                } else {
+                    mTvTime.setText("");
+                }
+
+                //Update the UI again in x milliseconds.
+                if (mHandler != null) {
+                    mHandler.postDelayed(this, UI_UPDATE_DELAY);
+                }
+            }
+        };
+
+        super.initUIHandler(runnable);
+    }
+
+    /**
+     * Shows initial instruction dialog.
+     */
+    @Override
+    protected void showInitialDialog() {
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+        builder.setMessage(R.string.phase2_initial_message)
+                .setTitle(getResources().getStringArray(R.array.phase)[TestActivity.CTSTest.ROBUSTNESS.ordinal()])
+                .setPositiveButton(R.string.got_it, null);
+
+        AlertDialog dialog = builder.create();
+        dialog.show();
+    }
+
+    @Override
+    public void onResult(final ResultObject result) {
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mResultGiven = true;
+                RobustnessResultDialog dialog = RobustnessResultDialog.newInstance(result);
+                dialog.setTargetFragment(RobustnessFragment.this, DIALOG_FRAGMENT);
+                dialog.show(getActivity().getFragmentManager(), "ResultDialogFragment");
+                mPlaceWaypointButton.setVisibility(View.INVISIBLE);
+
+                if (result.hasPassed() || BuildConfig.DEBUG) {
+                    mBtnPass.setEnabled(true);
+                    mBtnPass.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View view) {
+                            onReadyForPhase3();
+                        }
+                    });
+                }
+            }
+        });
+    }
+
+    private void onReadyForPhase3() {
+        mActivity.switchToStartFragment(TestActivity.CTSTest.COMPLEX_MOVEMENT);
+    }
+
+    @Override
+    public void onNewRotationData(RotationData data) {
+        synchronized (TIMER_LOCK) {
+            mIsPassing = data.getRotationTestState();
+        }
+
+        if (mRenderer != null) {
+            if (data.getRotationTestState()) {
+                ((RobustnessRenderer) mRenderer).setLineColor(Colour.GREEN);
+            } else {
+                ((RobustnessRenderer) mRenderer).setLineColor(Colour.RED);
+            }
+
+            if (mActivity.getUserGeneratedWaypoints(Manager.Lap.LAP_3).size() > 0) {
+                ((RobustnessRenderer) mRenderer).updateCurrentAngle(data.getCurrentAngle());
+                ((RobustnessRenderer) mRenderer).updateTargetAngle(data.getTargetAngle());
+            }
+        }
+    }
+}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/AccuracyListener.java
similarity index 72%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/AccuracyListener.java
index 27a6fe2..4b188f1 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/AccuracyListener.java
@@ -13,10 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.verifier.sensors.sixdof.Interfaces;
 
-package android.server.app;
+/**
+ * Interface that handles UI listeners that are only used in the Accuracy test.
+ */
+public interface AccuracyListener {
+    void onReset();
 
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
+    void lap1Complete();
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/BaseUiListener.java
similarity index 61%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/BaseUiListener.java
index 27a6fe2..302bdd6 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/BaseUiListener.java
@@ -13,10 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.verifier.sensors.sixdof.Interfaces;
 
-package android.server.app;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
 
-import android.app.Activity;
+/**
+ * Interface that handles UI listeners that are used in every test.
+ */
+public interface BaseUiListener {
+    void onPoseProviderReady();
 
-public class BottomLeftLayoutActivity extends Activity {
+    void onWaypointPlaced();
+
+    void onResult(ResultObject result);
+
+    void onDestroyUi();
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/ComplexMovementListener.java
similarity index 65%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/ComplexMovementListener.java
index 27a6fe2..7f3bfe9 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/ComplexMovementListener.java
@@ -13,10 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.verifier.sensors.sixdof.Interfaces;
 
-package android.server.app;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring;
 
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
+/**
+ * Interface that handles UI listeners that are only used in the Complex Movement test.
+ */
+public interface ComplexMovementListener {
+    void onRingEntered(Ring ring);
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/RobustnessListener.java
similarity index 65%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/RobustnessListener.java
index 27a6fe2..7821322 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/RobustnessListener.java
@@ -13,10 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.verifier.sensors.sixdof.Interfaces;
 
-package android.server.app;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.RotationData;
 
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
+/**
+ * Interface that handles UI listeners that are only used in the Robustness test.
+ */
+public interface RobustnessListener {
+    void onNewRotationData(RotationData data);
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/AccuracyRenderer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/AccuracyRenderer.java
new file mode 100644
index 0000000..287b31a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/AccuracyRenderer.java
@@ -0,0 +1,40 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer;
+
+import android.content.Context;
+
+/**
+ * Renderer for the Accuracy test.
+ */
+public class AccuracyRenderer extends BaseRenderer {
+    public AccuracyRenderer(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected void doPreRenderingSetup() {
+        // Set view and projection matrix to orthogonal so that camera preview fills the screen.
+        mViewMatrix = mOrthogonalViewMatrix;
+        mProjectionMatrix = mOrthogonalProjectionMatrix;
+    }
+
+    @Override
+    protected void doTestSpecificRendering() {
+        // Update the texture with the latest camera frame if there is an update pending.
+        updateCameraTexture();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/BaseRenderer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/BaseRenderer.java
new file mode 100644
index 0000000..bac1935
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/BaseRenderer.java
@@ -0,0 +1,344 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.CameraStreamManager;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.DrawParameters;
+import com.android.cts.verifier.sensors.sixdof.Renderer.Renderable.CameraPreviewRenderable;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.PoseProvider;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.MATRIX_4X4;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.ORIENTATION_360_ANTI_CLOCKWISE;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.opengl.Matrix;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.WindowManager;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Abstract class that connects to Android Camera to use as an OpenGL texture.
+ */
+public abstract class BaseRenderer implements GLSurfaceView.Renderer {
+    private static final String TAG = "BaseRenderer";
+    private static final int ORIENTATION_COUNT = 4;
+
+    protected float[] mViewMatrix = new float[MATRIX_4X4];
+    protected float[] mOrthogonalViewMatrix = new float[MATRIX_4X4];
+    protected float[] mProjectionMatrix = new float[MATRIX_4X4];
+
+    protected float[] mOrthogonalProjectionMatrix = new float[MATRIX_4X4];
+    protected float[] mFrustrumProjectionMatrix = new float[MATRIX_4X4];
+
+    protected DrawParameters mDrawParameters;
+
+    protected float[] mCameraCoordinates;
+
+    protected PoseProvider mPoseProvider;
+    protected boolean mIsValid = false;
+
+    protected CameraPreviewRenderable mCameraPreview;
+    protected double mLastRGBFrameTimestamp = -1;
+
+    private int mCameraPreviewRotation = 0;
+
+    protected int mOpenGlRotation = 0;
+    protected float[] mOpenGlUpVector;
+
+    private Context mContext;
+
+    public BaseRenderer(Context context) {
+        mContext = context;
+        mOpenGlRotation = getDeviceRotation(context);
+        mOpenGlUpVector = getUpVector(mOpenGlRotation);
+        mCameraPreviewRotation = CameraStreamManager.getRotation(context, mOpenGlRotation);
+    }
+
+    @Override
+    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
+        // Set the background clear color to black.
+        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+        // Enable depth testing
+        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
+
+        mCameraPreview = new CameraPreviewRenderable();
+
+        resetViewMatrix();
+    }
+
+    protected void resetViewMatrix() {
+        // Position the eye in front of the origin.
+        final float eyeX = 0.0f;
+        final float eyeY = 0.0f;
+        final float eyeZ = 0.0f;
+
+        // We are looking toward the distance
+        final float lookX = 0.0f;
+        final float lookY = 0.0f;
+        final float lookZ = -5.0f;
+
+        // Set our up vector. This is where our head would be pointing were we holding the camera.
+        float[] upVector = getUpVector(mCameraPreviewRotation);
+
+        // Set the view matrix.
+        Matrix.setLookAtM(mViewMatrix, 0,
+                eyeX, eyeY, eyeZ,
+                lookX, lookY, lookZ,
+                upVector[X], upVector[Y], upVector[Z]);
+        Matrix.setLookAtM(mOrthogonalViewMatrix, 0,
+                eyeX, eyeY, eyeZ,
+                lookX, lookY, lookZ,
+                upVector[X], upVector[Y], upVector[Z]);
+    }
+
+    @Override
+    public void onSurfaceChanged(GL10 glUnused, int width, int height) {
+        // Set the OpenGL viewport to the same size as the surface.
+        GLES20.glViewport(0, 0, width, height);
+
+        // Create a new perspective projection matrix. The height will stay the same
+        // while the width will vary as per aspect ratio.
+        // This project matrix does not take into account the camera intrinsics and should not be
+        // used for AR purposes.
+        final float ratio = (float) width / height;
+        float left = -ratio;
+        float right = ratio;
+        float bottom = -1.0f;
+        float top = 1.0f;
+        final float near = 1.0f;
+        final float far = 10.0f;
+
+        boolean invertAxis = false;
+
+        switch (mCameraPreviewRotation) {
+            case MathsUtils.ORIENTATION_0:
+            case MathsUtils.ORIENTATION_180_ANTI_CLOCKWISE:
+            case MathsUtils.ORIENTATION_360_ANTI_CLOCKWISE:
+                break;
+            case MathsUtils.ORIENTATION_90_ANTI_CLOCKWISE:
+            case MathsUtils.ORIENTATION_270_ANTI_CLOCKWISE:
+                // Invert aspect ratio.
+                invertAxis = true;
+                bottom = -ratio;
+                top = ratio;
+                left = -1.0f;
+                right = 1.0f;
+                break;
+            default:
+                // Unexpected orientation, error out.
+                throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
+        }
+
+        mCameraCoordinates = getCameraCoordinates(left, right, bottom, top);
+
+        // Give camera preview reference to the context so that it can connect to the camera.
+        mCameraPreview.initialiseCameraPreview(mCameraCoordinates, invertAxis, mContext);
+
+        Matrix.orthoM(mOrthogonalProjectionMatrix, 0, left, right, bottom, top, near, far);
+        Matrix.frustumM(mFrustrumProjectionMatrix, 0, left, right, bottom, top, near, far);
+
+        mProjectionMatrix = mOrthogonalProjectionMatrix;
+
+        mDrawParameters = new DrawParameters();
+
+        mIsValid = true;
+    }
+
+    @Override
+    public void onDrawFrame(GL10 glUnused) {
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
+        doPreRenderingSetup();
+        doCoreRendering();
+        doTestSpecificRendering();
+    }
+
+    private void doCoreRendering() {
+        mDrawParameters.update(mViewMatrix, mProjectionMatrix);
+        mCameraPreview.draw(mDrawParameters);
+    }
+
+    protected synchronized void updateCameraTexture() {
+        mLastRGBFrameTimestamp = mCameraPreview.updateTexture();
+    }
+
+    /**
+     * Setup up view and projecttion matrices to be the ones you want for this draw call.
+     */
+    protected abstract void doPreRenderingSetup();
+
+    /**
+     * Do rendering that is unique to each test.
+     */
+    protected abstract void doTestSpecificRendering();
+
+    /**
+     * Where to position the camera preview on the screen. Can be overridden by sub classes.
+     */
+    protected float[] getCameraCoordinates(float left, float right, float bottom, float top) {
+        switch (mCameraPreviewRotation) {
+            case MathsUtils.ORIENTATION_0:
+            case MathsUtils.ORIENTATION_180_ANTI_CLOCKWISE:
+            case MathsUtils.ORIENTATION_360_ANTI_CLOCKWISE:
+                // Normal aspect ratio.
+                return new float[]{
+                        left, top, 0.0f,
+                        left, bottom, 0.0f,
+                        right, top, 0.0f,
+                        left, bottom, 0.0f,
+                        right, bottom, 0.0f,
+                        right, top, 0.0f,
+                };
+            case MathsUtils.ORIENTATION_90_ANTI_CLOCKWISE:
+            case MathsUtils.ORIENTATION_270_ANTI_CLOCKWISE:
+                // Inverted aspect ratio.
+                return new float[]{
+                        bottom, right, 0.0f,
+                        bottom, left, 0.0f,
+                        top, right, 0.0f,
+                        bottom, left, 0.0f,
+                        top, left, 0.0f,
+                        top, right, 0.0f,
+                };
+            default:
+                // Unexpected orientation, error out.
+                throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
+        }
+    }
+
+
+    /**
+     * Saves PoseProvider object for later so we can connect to camera at appropriate time.
+     */
+    public void connectCamera(PoseProvider poseProvider, Context context) {
+        // Save these for later so we can connect to camera after mCameraPreview has been
+        // initialised. Also used to setup extrinsics in ComplexMovementRenderer.
+        mPoseProvider = poseProvider;
+        mContext = context;
+    }
+
+    public void disconnectCamera() {
+        mCameraPreview.disconnectCamera();
+    }
+
+    public void onDestroy() {
+        mPoseProvider = null;
+        mContext = null;
+
+        if (mCameraPreview != null) {
+            mCameraPreview.destroy();
+            mCameraPreview = null;
+        }
+    }
+
+    private static float[] getUpVector(int rotation) {
+        float [] upVector = new float[MathsUtils.VECTOR_3D];
+
+        switch (rotation) {
+            case MathsUtils.ORIENTATION_0:
+            case ORIENTATION_360_ANTI_CLOCKWISE:
+                upVector[X] = 0.0f;
+                upVector[Y] = 1.0f;
+                upVector[Z] = 0.0f;
+                break;
+            case MathsUtils.ORIENTATION_90_ANTI_CLOCKWISE:
+                upVector[X] = -1.0f;
+                upVector[Y] = 0.0f;
+                upVector[Z] = 0.0f;
+                break;
+            case MathsUtils.ORIENTATION_180_ANTI_CLOCKWISE:
+                upVector[X] = 0.0f;
+                upVector[Y] = -1.0f;
+                upVector[Z] = 0.0f;
+                break;
+            case MathsUtils.ORIENTATION_270_ANTI_CLOCKWISE:
+                upVector[X] = 1.0f;
+                upVector[Y] = 0.0f;
+                upVector[Z] = 0.0f;
+                break;
+            default:
+                // Unexpected orientation, error out.
+                throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
+        }
+
+        return upVector;
+    }
+
+    public static int getDeviceRotation(Context context) {
+        WindowManager windowManager = (WindowManager)
+                context.getSystemService(Context.WINDOW_SERVICE);
+        final Display display = windowManager.getDefaultDisplay();
+        int naturalOrientation = Configuration.ORIENTATION_LANDSCAPE;
+        int configOrientation = context.getResources().getConfiguration().orientation;
+        switch (display.getRotation()) {
+            case Surface.ROTATION_0:
+            case Surface.ROTATION_180:
+                // We are currently in the same basic orientation as the natural orientation.
+                naturalOrientation = configOrientation;
+                break;
+            case Surface.ROTATION_90:
+            case Surface.ROTATION_270:
+                // We are currently in the other basic orientation to the natural orientation.
+                naturalOrientation = (configOrientation == Configuration.ORIENTATION_LANDSCAPE) ?
+                        Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
+                break;
+            default:
+                // Unexpected orientation, error out.
+                throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
+        }
+
+        // Since the map starts at portrait, we need to offset if this device's natural orientation
+        // is landscape.
+        int indexOffset = 0;
+        if (naturalOrientation == Configuration.ORIENTATION_LANDSCAPE) {
+            indexOffset = 1;
+        }
+
+        // Get rotation as a clockwise rotation.
+        int currentRotation = ORIENTATION_COUNT - display.getRotation();
+
+        // Check for reverse rotation direction and currentRotation if required.
+        try {
+            if (context.getResources().getBoolean(context.getResources().getSystem().getIdentifier(
+                    "config_reverseDefaultRotation", "bool", "android"))) {
+                currentRotation = display.getRotation();
+            }
+        } catch (Resources.NotFoundException e) {
+            // If resource is not found, assume default rotation and continue.
+            Log.d(TAG, "Cannot determine device rotation direction, assuming default");
+        }
+
+        int currentOrientation = (currentRotation + indexOffset);
+        int defaultOrientation = indexOffset;
+
+        int difference = (currentOrientation - defaultOrientation) % ORIENTATION_COUNT;
+        difference = difference * 90;
+
+        return difference;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/ComplexMovementRenderer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/ComplexMovementRenderer.java
new file mode 100644
index 0000000..3ac6b21
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/ComplexMovementRenderer.java
@@ -0,0 +1,262 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ModelMatrixCalculator;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ObjImporter;
+import com.android.cts.verifier.sensors.sixdof.Renderer.Renderable.ConeRenderable;
+import com.android.cts.verifier.sensors.sixdof.Renderer.Renderable.Light;
+import com.android.cts.verifier.sensors.sixdof.Renderer.Renderable.RingRenderable;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring;
+import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.Intrinsics;
+import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.PoseData;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.MATRIX_4X4;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.opengl.GLES20;
+import android.opengl.Matrix;
+
+import java.util.ArrayList;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Renderer for the robustness test
+ */
+public class ComplexMovementRenderer extends BaseRenderer {
+    private static final String TAG = "ComplexMovementRenderer";
+    private static final float[] DEFAULT_LIGHT_POSITION = new float[]{
+            0.0f, 3.0f, 0.0f};
+    private static final Object RING_LOCK = new Object();
+    private ModelMatrixCalculator mCameraModelMatrixCalculator;
+    private ConeRenderable mCone;
+    private Light mLight;
+    private float[] mPoseViewMatrix = new float[MATRIX_4X4];
+    private float[] mAugmentedRealityProjectMatrix = new float[MATRIX_4X4];
+
+    protected boolean mIsCameraConfigured = false;
+
+    protected double mCameraPoseTimestamp = 0;
+    private PoseData mLastFramePose;
+
+    private Context mContext;
+
+    private int mWaypointCount = 0;
+    private MediaPlayer mMediaPlayer;
+    private ArrayList<Ring> mRings;
+
+    public ComplexMovementRenderer(Context context, ArrayList<Ring> rings) {
+        super(context);
+        mCameraModelMatrixCalculator = new ModelMatrixCalculator(mOpenGlRotation);
+        mContext = context;
+        mMediaPlayer = MediaPlayer.create(context, R.raw.ring_sound);
+        mRings = rings;
+    }
+
+    @Override
+    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
+        super.onSurfaceCreated(glUnused, config);
+        mCone = new ConeRenderable(mOpenGlRotation, mOpenGlUpVector);
+        mLight = new Light(DEFAULT_LIGHT_POSITION, 2.0f);
+        setUpExtrinsics();
+
+        ObjImporter.ObjectData ringData = ObjImporter.parse(mContext.getResources(), R.raw.ring_obj);
+
+        for (Ring ring : mRings) {
+            final float[] position =
+                    MathsUtils.convertToOpenGlCoordinates(ring.getLocation(), mOpenGlRotation);
+            final float[] rotation =
+                    MathsUtils.convertToOpenGlCoordinates(ring.getRingRotation(), mOpenGlRotation);
+            RingRenderable ringRenderable = new RingRenderable(position, rotation, mOpenGlUpVector);
+            ringRenderable.initialise(ringData);
+            ring.setRingRenderable(ringRenderable);
+        }
+
+        ObjImporter.ObjectData coneData = ObjImporter.parse(mContext.getResources(), R.raw.cone_obj);
+        mCone.initialise(coneData);
+    }
+
+    @Override
+    protected void doPreRenderingSetup() {
+        // Set up drawing of background camera preview (orthogonal).
+        mViewMatrix = mOrthogonalViewMatrix;
+        mProjectionMatrix = mOrthogonalProjectionMatrix;
+    }
+
+    @Override
+    protected void doTestSpecificRendering() {
+        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT);
+        if (mPoseProvider != null) {
+            // Update the texture with the latest camera frame.
+            updateCameraTexture();
+
+            // We delay the camera set-up until now because if we do it earlier (i.e., when the
+            // camera is connected to the renderer) the PoseProvider service may still not have the
+            // necessary intrinsic and extrinsic transformation information available.
+            if (!mIsCameraConfigured) {
+                configureCamera();
+            }
+
+            // Calculate the device pose at the camera frame update time.
+            mLastFramePose = mPoseProvider.getLatestPoseData();
+            // Update the camera pose from the renderer
+            updateRenderCameraPose(mLastFramePose);
+            // Update the MV matrix with new pose data.
+            updatePoseViewMatrix();
+            // Update light with new translation.
+            mLight.updateLightPosition(MathsUtils.convertToOpenGlCoordinates(
+                    mLastFramePose.getTranslationAsFloats(), mOpenGlRotation));
+            mCameraPoseTimestamp = mLastFramePose.timestamp;
+        }
+
+        // Render objects with latest pose information available.
+        renderAugmentedRealityObjects();
+    }
+
+    private void renderAugmentedRealityObjects() {
+        // Set up projection matrix to match camera intrinsics.
+        mProjectionMatrix = mAugmentedRealityProjectMatrix;
+        // Set up view matrix to match current device positioning.
+        mViewMatrix = mPoseViewMatrix;
+
+        mDrawParameters.update(mViewMatrix, mProjectionMatrix, mLight);
+        for (Ring ring : mRings) {
+            // If we have placed the initial waypoint, we want rings for the first path, path 0.
+            if (ring.getPathNumber() == mWaypointCount && !ring.isEntered()) {
+                // Only draw the rings that are on our current path and have not been entered.
+                ring.getRingRenderable().draw(mDrawParameters);
+            }
+        }
+        // Clear depth buffer so cone does not clip with rings.
+        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT);
+
+        // Set cone to look at nearest ring.
+        boolean lookingAt = false;
+        for (Ring ring : mRings) {
+            if (!ring.isEntered() && !lookingAt && ring.getPathNumber() == mWaypointCount) {
+                // If the ring has not been entered, the cone has not been set to look at anything
+                // yet, and we are on the correct lap for this ring.
+
+                mCone.updateModelMatrix(mLastFramePose.getTranslationAsFloats(),
+                        mLastFramePose.getRotationAsFloats(), ring.getLocation());
+                lookingAt = true;
+            }
+        }
+
+        if (lookingAt) {
+            // Only draw the cone if it has something to look at.
+            mCone.draw(mDrawParameters);
+        }
+    }
+
+    protected void configureCamera() {
+        // This should never happen, but it never hurts to double-check.
+        if (mPoseProvider == null) {
+            return;
+        }
+
+        Intrinsics intrinsics = mPoseProvider.getIntrinsics();
+
+        mAugmentedRealityProjectMatrix = calculateProjectionMatrix(
+                intrinsics.getWidth(), intrinsics.getHeight(),
+                intrinsics.getFocalLengthInPixelsX(), intrinsics.getFocalLengthInPixelsY());
+        mIsCameraConfigured = true;
+    }
+
+    /**
+     * Called when a waypoint is placed in the last test. Used to show and hide rings.
+     *
+     * @param waypointCount Number of waypoints placed.
+     */
+    public void onWaypointPlaced(int waypointCount) {
+        mWaypointCount = waypointCount;
+    }
+
+    /**
+     * Called when a ring has been entered. Plays a sound and then hides the ring.
+     *
+     * @param ring Ring that has just been entered.
+     */
+    public void onRingEntered(Ring ring) {
+        synchronized (RING_LOCK) {
+            ring.setSoundPlayed(true);
+        }
+        mMediaPlayer.start();
+    }
+
+    /**
+     * Setup the extrinsics of the device.
+     */
+    private void setUpExtrinsics() {
+    }
+
+    /**
+     * Update the scene camera based on the provided pose. The
+     * device pose should match the pose of the device at the time the last rendered RGB frame.
+     */
+    public void updateRenderCameraPose(PoseData devicePose) {
+        mCameraModelMatrixCalculator.updateModelMatrix(devicePose.getTranslationAsFloats(),
+                devicePose.getRotationAsFloats());
+    }
+
+    /**
+     * Update the view matrix of the Renderer to follow the position of the device in the current
+     * perspective.
+     */
+    public void updatePoseViewMatrix() {
+        float[] invertModelMat = new float[MATRIX_4X4];
+        Matrix.setIdentityM(invertModelMat, 0);
+
+        float[] temporaryMatrix = new float[MATRIX_4X4];
+        Matrix.setIdentityM(temporaryMatrix, 0);
+
+        Matrix.setIdentityM(mPoseViewMatrix, 0);
+        Matrix.invertM(invertModelMat, 0,
+                mCameraModelMatrixCalculator.getModelMatrix(), 0);
+        Matrix.multiplyMM(temporaryMatrix, 0, mPoseViewMatrix, 0,
+                invertModelMat, 0);
+        System.arraycopy(temporaryMatrix, 0, mPoseViewMatrix, 0, MATRIX_4X4);
+    }
+
+    /**
+     * Use camera intrinsics to calculate the projection Matrix.
+     */
+    private float[] calculateProjectionMatrix(int width, int height,
+                                              double focalLengthX, double focalLengthY) {
+        // Uses frustumM to create a projection matrix taking into account calibrated camera
+        // intrinsic parameter.
+        // Reference: http://ksimek.github.io/2013/06/03/calibrated_cameras_in_opengl/
+        float near = 0.1f;
+        float far = 100f;
+
+        float xScale = (float) (near / focalLengthX);
+        float yScale = (float) (near / focalLengthY);
+
+        float[] projectionMatrix = new float[16];
+        Matrix.frustumM(projectionMatrix, 0,
+                xScale * -width / 2.0f,
+                xScale * width / 2.0f,
+                yScale * -height / 2.0f,
+                yScale * height / 2.0f,
+                near, far);
+        return projectionMatrix;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/CameraStreamManager.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/CameraStreamManager.java
new file mode 100644
index 0000000..c2d6f80
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/CameraStreamManager.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright 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.verifier.sensors.sixdof.Renderer.RenderUtils;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.util.Size;
+import android.view.Display;
+import android.view.Surface;
+import android.view.WindowManager;
+
+import java.util.Arrays;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@TargetApi(21)
+public class CameraStreamManager {
+
+    private Context mContext;
+    private SurfaceTexture mSurfaceTextureToStreamTo;
+    private int mWidth;
+    private int mHeight;
+
+    /**
+     * Tag for the {@link Log}.
+     */
+    private static final String TAG = "Camera2BasicFragment";
+
+    /**
+     * ID of the current {@link CameraDevice}.
+     */
+    private static final String CAMERA_ID = "0";
+
+    /**
+     * A {@link CameraCaptureSession } for camera preview.
+     */
+    private CameraCaptureSession mCaptureSession;
+
+    /**
+     * A reference to the opened {@link CameraDevice}.
+     */
+    private CameraDevice mCameraDevice;
+
+    /**
+     * The {@link android.util.Size} of camera preview.
+     */
+    private Size mPreviewSize;
+
+    /**
+     * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
+     */
+    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
+
+        @Override
+        public void onOpened(CameraDevice cameraDevice) {
+            // This method is called when the camera is opened.  We start camera preview here.
+            mCameraOpenCloseLock.release();
+            mCameraDevice = cameraDevice;
+            createCameraPreviewSession();
+        }
+
+        @Override
+        public void onDisconnected(CameraDevice cameraDevice) {
+            mCameraOpenCloseLock.release();
+            cameraDevice.close();
+            mCameraDevice = null;
+        }
+
+        @Override
+        public void onError(CameraDevice cameraDevice, int error) {
+            mCameraOpenCloseLock.release();
+            cameraDevice.close();
+            mCameraDevice = null;
+            Log.e(TAG, "onError " + error);
+        }
+
+    };
+
+    /**
+     * An additional thread for running tasks that shouldn't block the UI.
+     */
+    private HandlerThread mBackgroundThread;
+
+    /**
+     * A {@link Handler} for running tasks in the background.
+     */
+    private Handler mBackgroundHandler;
+
+    /**
+     * {@link CaptureRequest.Builder} for the camera preview
+     */
+    private CaptureRequest.Builder mPreviewRequestBuilder;
+
+    /**
+     * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
+     */
+    private CaptureRequest mPreviewRequest;
+
+    /**
+     * A {@link Semaphore} to prevent the app from exiting before closing the camera.
+     */
+    private Semaphore mCameraOpenCloseLock = new Semaphore(1);
+
+    /**
+     * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
+     */
+    /**
+     * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
+     */
+    private CameraCaptureSession.CaptureCallback mCaptureCallback
+            = new CameraCaptureSession.CaptureCallback() {
+
+        @Override
+        public void onCaptureProgressed(CameraCaptureSession session,
+                                        CaptureRequest request,
+                                        CaptureResult partialResult) {
+            // Don't need to do anything here.
+        }
+
+        @Override
+        public void onCaptureCompleted(CameraCaptureSession session,
+                                       CaptureRequest request,
+                                       TotalCaptureResult result) {
+            // Don't need to do anything here.
+        }
+
+    };
+
+    public CameraStreamManager(Context context, SurfaceTexture textureToStreamTo,
+                               int width, int height) {
+        mContext = context;
+        mSurfaceTextureToStreamTo = textureToStreamTo;
+        mWidth = width;
+        mHeight = height;
+    }
+
+    public void onStartCameraStream() {
+        startBackgroundThread();
+        openCamera(mWidth, mHeight);
+    }
+
+    public void onStopCameraStream() {
+        closeCamera();
+        stopBackgroundThread();
+    }
+
+    /**
+     * Sets up member variables related to camera.
+     *
+     * @param width  The width of available size for camera preview
+     * @param height The height of available size for camera preview
+     */
+    private void setUpCameraOutputs(int width, int height) {
+        // Danger, W.R.! Attempting to use too large a preview size could  exceed the camera
+        // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
+        // garbage capture data.
+        mPreviewSize = new Size(width, height);
+    }
+
+    /**
+     * Opens the camera specified by {@link CameraStreamManager#CAMERA_ID}.
+     */
+    private void openCamera(int width, int height) {
+        setUpCameraOutputs(width, height);
+        CameraManager manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
+        try {
+            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
+                throw new RuntimeException("Time out waiting to lock camera opening.");
+            }
+            manager.openCamera(CAMERA_ID, mStateCallback, mBackgroundHandler);
+        } catch (CameraAccessException e) {
+            e.printStackTrace();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
+        }
+    }
+
+    /**
+     * Closes the current {@link CameraDevice}.
+     */
+    private void closeCamera() {
+        try {
+            mCameraOpenCloseLock.acquire();
+            if (null != mCaptureSession) {
+                mCaptureSession.close();
+                mCaptureSession = null;
+            }
+            if (null != mCameraDevice) {
+                mCameraDevice.close();
+                mCameraDevice = null;
+            }
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
+        } finally {
+            mCameraOpenCloseLock.release();
+        }
+    }
+
+    /**
+     * Starts a background thread and its {@link Handler}.
+     */
+    private void startBackgroundThread() {
+        mBackgroundThread = new HandlerThread("CameraBackground");
+        mBackgroundThread.start();
+        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+    }
+
+    /**
+     * Stops the background thread and its {@link Handler}.
+     */
+    private void stopBackgroundThread() {
+        if (mBackgroundThread != null) {
+            mBackgroundThread.quitSafely();
+            try {
+                mBackgroundThread.join();
+                mBackgroundThread = null;
+                mBackgroundHandler = null;
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Creates a new {@link CameraCaptureSession} for camera preview.
+     */
+    private void createCameraPreviewSession() {
+        try {
+            assert mSurfaceTextureToStreamTo != null;
+
+            // We configure the size of default buffer to be the size of camera preview we want.
+            mSurfaceTextureToStreamTo.setDefaultBufferSize(mPreviewSize.getWidth(),
+                    mPreviewSize.getHeight());
+
+            // This is the output Surface we need to start preview.
+            Surface surface = new Surface(mSurfaceTextureToStreamTo);
+
+            // We set up a CaptureRequest.Builder with the output Surface.
+            mPreviewRequestBuilder
+                    = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+            mPreviewRequestBuilder.addTarget(surface);
+
+            // Here, we create a CameraCaptureSession for camera preview.
+            mCameraDevice.createCaptureSession(Arrays.asList(surface),
+                    new CameraCaptureSession.StateCallback() {
+
+                        @Override
+                        public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+                            // The camera is already closed.
+                            if (null == mCameraDevice) {
+                                return;
+                            }
+
+                            // When the session is ready, we start displaying the preview.
+                            mCaptureSession = cameraCaptureSession;
+                            try {
+                                // Auto focus should be continuous for camera preview.
+                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
+                                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+
+                                // Finally, we start displaying the camera preview.
+                                mPreviewRequest = mPreviewRequestBuilder.build();
+                                mCaptureSession.setRepeatingRequest(mPreviewRequest,
+                                        mCaptureCallback, mBackgroundHandler);
+                            } catch (CameraAccessException e) {
+                                e.printStackTrace();
+                            }
+                        }
+
+                        @Override
+                        public void onConfigureFailed(
+                                CameraCaptureSession cameraCaptureSession) {
+                            Log.e(TAG, "Camera configuration failed.");
+                        }
+                    }, null
+            );
+        } catch (CameraAccessException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static int getRotation(Context context, int deviceRotation) {
+        // Get offset from the RGB camera.
+        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
+        CameraCharacteristics characteristics = null;
+        try {
+            characteristics = manager.getCameraCharacteristics(CAMERA_ID + "");
+        } catch (CameraAccessException e) {
+            e.printStackTrace();
+        }
+        int toOrientate = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+
+        // Add RGB offset to current device rotation.
+        return toOrientate + deviceRotation;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/Colour.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/Colour.java
new file mode 100644
index 0000000..201d697
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/Colour.java
@@ -0,0 +1,37 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.RenderUtils;
+
+/**
+ * Contains static float arrays of colours. RGBA.
+ */
+public class Colour {
+    public static final float[] GREEN = new float[]{
+            0.0f, 1.0f, 0.0f, 0.0f
+    };
+
+    public static final float[] RED = new float[]{
+            1.0f, 0.0f, 0.0f, 0.0f
+    };
+
+    public static final float[] YELLOW = new float[]{
+            1.0f, 1.0f, 0.0f, 0.0f
+    };
+
+    public static final float[] WHITE = new float[]{
+            1.0f, 1.0f, 1.0f, 0.0f
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ConeModelMatrixCalculator.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ConeModelMatrixCalculator.java
new file mode 100644
index 0000000..578dc9c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ConeModelMatrixCalculator.java
@@ -0,0 +1,80 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.RenderUtils;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.Renderable.ConeRenderable;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+
+import android.opengl.Matrix;
+
+/**
+ * Manages the model matrix of the direction cone.
+ */
+public class ConeModelMatrixCalculator extends ModelMatrixCalculator {
+    float[] mUpVector;
+
+    public ConeModelMatrixCalculator(int toRotate, float[] upVector) {
+        super(toRotate);
+        mUpVector = upVector;
+    }
+
+    public void updateModelMatrix(float[] translation, float[] quaternion, float[] lookAtPosition) {
+        float[] convertedTranslation = MathsUtils.convertToOpenGlCoordinates(translation, mToRotate);
+        // Calculate the extrinsics based model matrix with current pose data.
+        float[] newModelMatrix = calculateModelMatrix(convertedTranslation, quaternion);
+
+        // Extract the information we need from calculated model matrix. (Just the translation).
+        float[] translationMatrix = new float[MathsUtils.MATRIX_4X4];
+        Matrix.setIdentityM(translationMatrix, 0);
+        Matrix.translateM(translationMatrix, 0, newModelMatrix[MATRIX_4X4_TRANSLATION_X],
+                newModelMatrix[MATRIX_4X4_TRANSLATION_Y], newModelMatrix[MATRIX_4X4_TRANSLATION_Z]);
+
+        float[] openGlRingPosition = MathsUtils.convertToOpenGlCoordinates(lookAtPosition, mToRotate);
+        float[] rotationTransformation = new float[MathsUtils.MATRIX_4X4];
+        // Calculate direction vector.
+        float[] relativeVector = new float[MathsUtils.VECTOR_3D];
+        for (int i = 0; i < relativeVector.length; i++) {
+            relativeVector[i] = openGlRingPosition[i] - convertedTranslation[i];
+        }
+        Matrix.setIdentityM(rotationTransformation, 0);
+        // Calculate look at rotation transformation.
+        // Has to be relative to the origin otherwise we get some warping of the cone.
+        MathsUtils.setLookAtM(rotationTransformation,
+                // Where we are.
+                0.0f, 0.0f, 0.0f,
+                // What we want to look at.
+                relativeVector[X], relativeVector[Y], relativeVector[Z],
+                // Up direction.
+                mUpVector[X], mUpVector[Y], mUpVector[Z]);
+
+        // Apply translation to the look at matrix.
+        Matrix.multiplyMM(mModelMatrix, 0, translationMatrix, 0, rotationTransformation, 0);
+    }
+
+    /**
+     * Rotations that need to be done before rotating. Used for calculating the CONE_OFFSET.
+     *
+     * @return The offset that the cone needs to be at.
+     */
+    @Override
+    protected float[] getRequiredTranslations() {
+        return ConeRenderable.CONE_OFFSET;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/DrawParameters.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/DrawParameters.java
new file mode 100644
index 0000000..8664c72
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/DrawParameters.java
@@ -0,0 +1,49 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.RenderUtils;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.Renderable.Light;
+
+/**
+ * Parameters to be passed on a draw call
+ */
+public class DrawParameters {
+    private float[] mViewMatrix;
+    private float[] mProjectionMatrix;
+    private Light mLight;
+
+    public void update(float[] viewMatrix, float[] projectionMatrix) {
+        mViewMatrix = viewMatrix;
+        mProjectionMatrix = projectionMatrix;
+    }
+
+    public void update(float[] viewMatrix, float[] projectionMatrix, Light light) {
+        update(viewMatrix, projectionMatrix);
+        mLight = light;
+    }
+
+    public float[] getViewMatrix() {
+        return mViewMatrix;
+    }
+
+    public float[] getProjectionMatrix() {
+        return mProjectionMatrix;
+    }
+
+    public Light getLight() {
+        return mLight;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ModelMatrixCalculator.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ModelMatrixCalculator.java
new file mode 100644
index 0000000..3713305
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ModelMatrixCalculator.java
@@ -0,0 +1,159 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.RenderUtils;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.MATRIX_4X4;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+
+import android.opengl.Matrix;
+
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+
+
+/**
+ * Utility class to manage the calculation of a Model Matrix from the translation and quaternion
+ * arrays obtained from an PoseData object.
+ */
+public class ModelMatrixCalculator {
+
+    protected static final int MATRIX_4X4_TRANSLATION_X = 12;
+    protected static final int MATRIX_4X4_TRANSLATION_Y = 13;
+    protected static final int MATRIX_4X4_TRANSLATION_Z = 14;
+
+    public static final float[] TANGO_TO_OPENGL = new float[]{1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, -1.0f, 0.0f,
+            0.0f, 1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f};
+
+    protected float[] mModelMatrix = new float[MATRIX_4X4];
+
+    // Set these to identity matrix.
+    protected float[] mDevice2IMUMatrix = new float[]{1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+            1.0f};
+    protected float[] mColorCamera2IMUMatrix = new float[]{1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 1.0f};
+    protected float[] mOpengl2ColorCameraMatrix = new float[]{1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 1.0f};
+
+    protected int mToRotate = 0;
+
+    public ModelMatrixCalculator(int toRotate) {
+        Matrix.setIdentityM(mModelMatrix, 0);
+        mToRotate = toRotate;
+    }
+
+    /**
+     * Calculates a new model matrix, taking into account extrinsics and the latest pose
+     * data.
+     *
+     * @param translationInOpenGlCoordinates latest translation from pose data in OpenGl coordinate
+     *                                       system.
+     * @param quaternion                     latest rotation from pose data.
+     * @return the new model matrix.
+     */
+    protected float[] calculateModelMatrix(float[] translationInOpenGlCoordinates,
+                                           float[] quaternion) {
+        float[] newModelMatrix = new float[MATRIX_4X4];
+
+        // Calculate an initial matrix with extrinsics taken into account.
+        float[] imu2OpenGlMatrix = new float[MATRIX_4X4];
+        Matrix.setIdentityM(imu2OpenGlMatrix, 0);
+        Matrix.multiplyMM(imu2OpenGlMatrix, 0, mColorCamera2IMUMatrix, 0,
+                mOpengl2ColorCameraMatrix, 0);
+        float[] invertedDevice2ImuMatrix = new float[MATRIX_4X4];
+        Matrix.setIdentityM(invertedDevice2ImuMatrix, 0);
+        Matrix.invertM(invertedDevice2ImuMatrix, 0, mDevice2IMUMatrix, 0);
+        float[] extrinsicsBasedMatrix = new float[MATRIX_4X4];
+        Matrix.setIdentityM(extrinsicsBasedMatrix, 0);
+        Matrix.multiplyMM(extrinsicsBasedMatrix, 0, invertedDevice2ImuMatrix, 0,
+                imu2OpenGlMatrix, 0);
+
+        // Do any translations that need to be done before rotating. Only used for the Cone offset.
+        float[] requiredTranslations = getRequiredTranslations();
+        Matrix.translateM(extrinsicsBasedMatrix, 0, requiredTranslations[X], requiredTranslations[Y],
+                requiredTranslations[Z]);
+
+        // Rotate based on rotation pose data.
+        float[] quaternionMatrix = new float[MATRIX_4X4];
+        Matrix.setIdentityM(quaternionMatrix, 0);
+        quaternionMatrix = MathsUtils.quaternionMatrixOpenGL(quaternion);
+        float[] rotatedMatrix = new float[MATRIX_4X4];
+        float[] deviceOrientationMatrix = new float[MATRIX_4X4];
+        Matrix.setIdentityM(rotatedMatrix, 0);
+        Matrix.setIdentityM(newModelMatrix, 0);
+        Matrix.setIdentityM(deviceOrientationMatrix, 0);
+        Matrix.multiplyMM(rotatedMatrix, 0, quaternionMatrix, 0,
+                extrinsicsBasedMatrix, 0);
+        Matrix.multiplyMM(deviceOrientationMatrix, 0, TANGO_TO_OPENGL, 0,
+                rotatedMatrix, 0);
+
+        Matrix.multiplyMM(newModelMatrix, 0, deviceOrientationMatrix, 0,
+                MathsUtils.getDeviceOrientationMatrix(mToRotate), 0);
+
+        // Finally, add the translations from the pose data.
+        newModelMatrix[MATRIX_4X4_TRANSLATION_X] += translationInOpenGlCoordinates[X];
+        newModelMatrix[MATRIX_4X4_TRANSLATION_Y] += translationInOpenGlCoordinates[Y];
+        newModelMatrix[MATRIX_4X4_TRANSLATION_Z] += translationInOpenGlCoordinates[Z];
+
+        return newModelMatrix;
+    }
+
+    /**
+     * Updates the model matrix (rotation and translation).
+     *
+     * @param translation a three-element array of translation data.
+     * @param quaternion  a four-element array of rotation data.
+     */
+    public void updateModelMatrix(float[] translation, float[] quaternion) {
+        float[] convertedTranslation = MathsUtils.convertToOpenGlCoordinates(translation, mToRotate);
+        mModelMatrix = calculateModelMatrix(convertedTranslation, quaternion);
+    }
+
+    public void setDevice2IMUMatrix(float[] translation, float[] quaternion) {
+        mDevice2IMUMatrix = MathsUtils.quaternionMatrixOpenGL(quaternion);
+        mDevice2IMUMatrix[MATRIX_4X4_TRANSLATION_X] = translation[X];
+        mDevice2IMUMatrix[MATRIX_4X4_TRANSLATION_Y] = translation[Y];
+        mDevice2IMUMatrix[MATRIX_4X4_TRANSLATION_Z] = translation[Z];
+    }
+
+    public void setColorCamera2IMUMatrix(float[] translation, float[] quaternion) {
+        mOpengl2ColorCameraMatrix = new float[]{1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+                -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+                1.0f};
+        mColorCamera2IMUMatrix = MathsUtils.quaternionMatrixOpenGL(quaternion);
+        mColorCamera2IMUMatrix[MATRIX_4X4_TRANSLATION_X] = translation[X];
+        mColorCamera2IMUMatrix[MATRIX_4X4_TRANSLATION_Y] = translation[Y];
+        mColorCamera2IMUMatrix[MATRIX_4X4_TRANSLATION_Z] = translation[Z];
+    }
+
+    public float[] getModelMatrix() {
+        return mModelMatrix;
+    }
+
+    /**
+     * Translations that need to be done before rotating. Used for calculating the CONE_OFFSET.
+     *
+     * @return no translation.
+     */
+    protected float[] getRequiredTranslations() {
+        return new float[]{0.0f, 0.0f, 0.0f};
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ObjImporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ObjImporter.java
new file mode 100644
index 0000000..e6f01be
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ObjImporter.java
@@ -0,0 +1,209 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.RenderUtils;
+
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+/**
+ * Imports an .obj file into an ObjectData class so that it can be rendered by OpenGl. Based on the
+ * .obj importer from Rajawali.
+ */
+public class ObjImporter {
+    protected static final String TAG = "ObjImporter";
+    protected static final String VERTEX = "v";
+    protected static final String FACE = "f";
+    protected static final String NORMAL = "vn";
+
+    protected static class ObjIndexData {
+
+        public ArrayList<Integer> vertexIndices;
+        public ArrayList<Integer> texCoordIndices;
+        public ArrayList<Integer> colorIndices;
+        public ArrayList<Integer> normalIndices;
+
+        public ObjIndexData() {
+            vertexIndices = new ArrayList<Integer>();
+            texCoordIndices = new ArrayList<Integer>();
+            colorIndices = new ArrayList<Integer>();
+            normalIndices = new ArrayList<Integer>();
+        }
+    }
+
+    public static class ObjectData {
+        float[] mVertexData;
+        float[] mNormalsData;
+        int[] mIndicesData;
+
+        protected ObjectData(float[] vertexData, float[] normalsData, int[] indicesData) {
+            mVertexData = vertexData;
+            mNormalsData = normalsData;
+            mIndicesData = indicesData;
+        }
+
+        public float[] getVertexData() {
+            return mVertexData;
+        }
+
+        public float[] getNormalsData() {
+            return mNormalsData;
+        }
+
+        public int[] getIndicesData() {
+            return mIndicesData;
+        }
+    }
+
+    public static ObjectData parse(Resources mResources, int mResourceId) {
+        BufferedReader buffer = null;
+        InputStream fileIn = mResources.openRawResource(mResourceId);
+        buffer = new BufferedReader(new InputStreamReader(fileIn));
+        String line;
+        ObjIndexData currObjIndexData = new ObjIndexData();
+
+        ArrayList<Float> vertices = new ArrayList<Float>();
+        ArrayList<Float> texCoords = new ArrayList<Float>();
+        ArrayList<Float> normals = new ArrayList<Float>();
+
+        try {
+            while ((line = buffer.readLine()) != null) {
+                // Skip comments and empty lines.
+                if (line.length() == 0 || line.charAt(0) == '#')
+                    continue;
+                StringTokenizer parts = new StringTokenizer(line, " ");
+                int numTokens = parts.countTokens();
+
+                if (numTokens == 0)
+                    continue;
+                String type = parts.nextToken();
+
+                if (type.equals(VERTEX)) {
+                    vertices.add(Float.parseFloat(parts.nextToken()));
+                    vertices.add(Float.parseFloat(parts.nextToken()));
+                    vertices.add(Float.parseFloat(parts.nextToken()));
+                } else if (type.equals(FACE)) {
+                    boolean isQuad = numTokens == 5;
+                    int[] quadvids = new int[4];
+                    int[] quadtids = new int[4];
+                    int[] quadnids = new int[4];
+
+                    boolean emptyVt = line.indexOf("//") > -1;
+                    if (emptyVt) line = line.replace("//", "/");
+
+                    parts = new StringTokenizer(line);
+
+                    parts.nextToken();
+                    StringTokenizer subParts = new StringTokenizer(parts.nextToken(), "/");
+                    int partLength = subParts.countTokens();
+
+                    boolean hasuv = partLength >= 2 && !emptyVt;
+                    boolean hasn = partLength == 3 || (partLength == 2 && emptyVt);
+                    int idx;
+
+                    for (int i = 1; i < numTokens; i++) {
+                        if (i > 1)
+                            subParts = new StringTokenizer(parts.nextToken(), "/");
+                        idx = Integer.parseInt(subParts.nextToken());
+
+                        if (idx < 0) idx = (vertices.size() / 3) + idx;
+                        else idx -= 1;
+                        if (!isQuad)
+                            currObjIndexData.vertexIndices.add(idx);
+                        else
+                            quadvids[i - 1] = idx;
+                        if (hasuv) {
+                            idx = Integer.parseInt(subParts.nextToken());
+                            if (idx < 0) idx = (texCoords.size() / 2) + idx;
+                            else idx -= 1;
+                            if (!isQuad)
+                                currObjIndexData.texCoordIndices.add(idx);
+                            else
+                                quadtids[i - 1] = idx;
+                        }
+                        if (hasn) {
+                            idx = Integer.parseInt(subParts.nextToken());
+                            if (idx < 0) idx = (normals.size() / 3) + idx;
+                            else idx -= 1;
+                            if (!isQuad)
+                                currObjIndexData.normalIndices.add(idx);
+                            else
+                                quadnids[i - 1] = idx;
+                        }
+                    }
+
+                    if (isQuad) {
+                        int[] indices = new int[]{0, 1, 2, 0, 2, 3};
+
+                        for (int i = 0; i < 6; ++i) {
+                            int index = indices[i];
+                            currObjIndexData.vertexIndices.add(quadvids[index]);
+                            currObjIndexData.texCoordIndices.add(quadtids[index]);
+                            currObjIndexData.normalIndices.add(quadnids[index]);
+                        }
+                    }
+                } else if (type.equals(NORMAL)) {
+                    normals.add(Float.parseFloat(parts.nextToken()));
+                    normals.add(Float.parseFloat(parts.nextToken()));
+                    normals.add(Float.parseFloat(parts.nextToken()));
+                }
+            }
+
+            buffer.close();
+        } catch (IOException e) {
+            Log.e(TAG, "failed to parse", e);
+        }
+
+        int i;
+        float[] aVertices = new float[currObjIndexData.vertexIndices.size() * 3];
+        float[] aNormals = new float[currObjIndexData.normalIndices.size() * 3];
+        int[] aIndices = new int[currObjIndexData.vertexIndices.size()];
+
+        for (i = 0; i < currObjIndexData.vertexIndices.size(); ++i) {
+            int faceIndex = currObjIndexData.vertexIndices.get(i) * 3;
+            int vertexIndex = i * 3;
+            try {
+                aVertices[vertexIndex] = vertices.get(faceIndex);
+                aVertices[vertexIndex + 1] = vertices.get(faceIndex + 1);
+                aVertices[vertexIndex + 2] = vertices.get(faceIndex + 2);
+                aIndices[i] = i;
+            } catch (ArrayIndexOutOfBoundsException e) {
+                Log.d(TAG, "Obj array index out of bounds: " + vertexIndex + ", " + faceIndex);
+            }
+        }
+        for (i = 0; i < currObjIndexData.normalIndices.size(); ++i) {
+            int normalIndex = currObjIndexData.normalIndices.get(i) * 3;
+            int ni = i * 3;
+            if (normals.size() == 0) {
+                Log.e(TAG, "There are no normals specified for this model. " +
+                        "Please re-export with normals.");
+                throw new RuntimeException("[" + TAG + "] There are no normals specified " +
+                        "for this model. Please re-export with normals.");
+            }
+            aNormals[ni] = normals.get(normalIndex);
+            aNormals[ni + 1] = normals.get(normalIndex + 1);
+            aNormals[ni + 2] = normals.get(normalIndex + 2);
+        }
+
+        return new ObjectData(aVertices, aNormals, aIndices);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ShaderHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ShaderHelper.java
new file mode 100644
index 0000000..1188989
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RenderUtils/ShaderHelper.java
@@ -0,0 +1,216 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.RenderUtils;
+
+import android.opengl.GLES20;
+import android.util.Log;
+
+/**
+ * Contains shader code and helper functions for compiling them.
+ */
+public class ShaderHelper {
+    private static final String TAG = "ShaderHelper";
+
+    public static String getCameraPreviewFragmentShader() {
+        return "#extension GL_OES_EGL_image_external : require\n" +
+                "precision mediump float;\n" +
+                "uniform samplerExternalOES u_Texture;\n" +
+                "\n" +
+                "varying vec3 v_Position;\n" +
+                "varying vec2 v_TexCoordinate;\n" +
+                "\n" +
+                "void main()\n" +
+                "{\n" +
+                "    gl_FragColor = texture2D(u_Texture, v_TexCoordinate);\n" +
+                "}";
+    }
+
+    public static String getCameraPreviewVertexShader() {
+        return "uniform mat4 u_MVPMatrix;\n" +
+                "uniform mat4 u_MVMatrix;\n" +
+                "attribute vec4 a_Position;\n" +
+                "attribute vec2 a_TexCoordinate;\n" +
+                "\n" +
+                "varying vec3 v_Position;\n" +
+                "varying vec2 v_TexCoordinate;\n" +
+                "\n" +
+                "void main()\n" +
+                "{\n" +
+                "   v_Position = vec3(u_MVMatrix * a_Position);\n" +
+                "\n" +
+                "   v_TexCoordinate = a_TexCoordinate;\n" +
+                "\n" +
+                "   gl_Position = u_MVPMatrix * a_Position;\n" +
+                "}";
+    }
+
+    public static String getRectangleFragmentShader() {
+        return "precision mediump float;" +
+                "varying vec4 v_Color;" +
+                "varying vec3 v_Position;" +
+                "void main() {" +
+                "  gl_FragColor = v_Color;" +
+                "}";
+
+    }
+
+    public static String getRectangleVertexShader() {
+        return "uniform mat4 u_MVPMatrix;" +
+                "uniform mat4 u_MVMatrix;" +
+                "varying vec3 v_Position;" +
+                "varying vec4 v_Color;" +
+                "attribute vec4 a_Position;" +
+                "attribute vec4 a_Color;" +
+                "void main() {" +
+                "   v_Position = vec3(u_MVMatrix * a_Position);" +
+                "   v_Color = a_Color;" +
+                "   gl_Position = u_MVPMatrix * a_Position;" +
+                "}";
+    }
+
+    /**
+     * Contains lighting information for shadows that enhance AR effect.
+     *
+     * @return the vertex shader.
+     */
+    public static String getAugmentedRealityVertexShader() {
+        return "uniform mat4 u_MVPMatrix;\n"
+                + "uniform mat4 u_MVMatrix;\n"
+
+                + "attribute vec4 a_Position;\n"
+                + "attribute vec4 a_Color;\n"
+                + "attribute vec3 a_Normal;\n"
+
+                + "varying vec3 v_Position;\n"
+                + "varying vec4 v_Color;\n"
+                + "varying vec3 v_Normal;\n"
+
+                + "void main()\n"
+                + "{\n"
+                + "   v_Position = vec3(u_MVMatrix * a_Position);\n"
+                + "   v_Color = a_Color;\n"
+                + "   v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));\n"
+                + "   gl_Position = u_MVPMatrix * a_Position;\n"
+                + "}\n";
+    }
+
+    /**
+     * Contains lighting information for shadows that enhance AR effect.
+     *
+     * @return the fragment shader.
+     */
+    public static String getAugmentedRealityFragmentShader() {
+        return "precision mediump float;\n"
+                + "uniform vec3 u_LightPos;\n"
+                + "uniform float u_LightStrength;\n"
+                + "varying vec3 v_Position;\n"
+                + "varying vec4 v_Color;\n"
+                + "varying vec3 v_Normal;\n"
+
+                + "void main()\n"
+                + "{\n"
+                + "   float distance = length(u_LightPos - v_Position);\n"
+                + "   vec3 lightVector = normalize(u_LightPos - v_Position);\n"
+                + "   float diffuse = max(dot(v_Normal, lightVector), 0.25);\n"
+                + "   diffuse = diffuse * (u_LightStrength / (1.0 + (0.25 * distance * distance)));\n"
+                + "   gl_FragColor = v_Color * diffuse;\n"
+                + "}";
+    }
+
+    /**
+     * Helper function to compile a shader.
+     *
+     * @param shaderType   The shader type.
+     * @param shaderSource The shader source code.
+     * @return An OpenGL handle to the shader.
+     */
+    public static int compileShader(final int shaderType, final String shaderSource) {
+        int shaderHandle = GLES20.glCreateShader(shaderType);
+
+        if (shaderHandle != 0) {
+            // Pass in the shader source.
+            GLES20.glShaderSource(shaderHandle, shaderSource);
+
+            // Compile the shader.
+            GLES20.glCompileShader(shaderHandle);
+
+            // Get the compilation status.
+            final int[] compileStatus = new int[1];
+            GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
+
+            // If the compilation failed, delete the shader.
+            if (compileStatus[0] == 0) {
+                Log.e(TAG, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shaderHandle));
+                GLES20.glDeleteShader(shaderHandle);
+                shaderHandle = 0;
+            }
+        }
+
+        if (shaderHandle == 0) {
+            throw new RuntimeException("Error creating shader.");
+        }
+
+        return shaderHandle;
+    }
+
+    /**
+     * Helper function to compile and link a program.
+     *
+     * @param vertexShaderHandle   An OpenGL handle to an already-compiled vertex shader.
+     * @param fragmentShaderHandle An OpenGL handle to an already-compiled fragment shader.
+     * @param attributes           Attributes that need to be bound to the program.
+     * @return An OpenGL handle to the program.
+     */
+    public static int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) {
+        int programHandle = GLES20.glCreateProgram();
+
+        if (programHandle != 0) {
+            // Bind the vertex shader to the program.
+            GLES20.glAttachShader(programHandle, vertexShaderHandle);
+
+            // Bind the fragment shader to the program.
+            GLES20.glAttachShader(programHandle, fragmentShaderHandle);
+
+            // Bind attributes
+            if (attributes != null) {
+                final int size = attributes.length;
+                for (int i = 0; i < size; i++) {
+                    GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
+                }
+            }
+
+            // Link the two shaders together into a program.
+            GLES20.glLinkProgram(programHandle);
+
+            // Get the link status.
+            final int[] linkStatus = new int[1];
+            GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
+
+            // If the link failed, delete the program.
+            if (linkStatus[0] == 0) {
+                Log.e(TAG, "Error compiling program: " + GLES20.glGetProgramInfoLog(programHandle));
+                GLES20.glDeleteProgram(programHandle);
+                programHandle = 0;
+            }
+        }
+
+        if (programHandle == 0) {
+            throw new RuntimeException("Error creating program.");
+        }
+
+        return programHandle;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/CameraPreviewRenderable.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/CameraPreviewRenderable.java
new file mode 100644
index 0000000..2e9b685
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/CameraPreviewRenderable.java
@@ -0,0 +1,229 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.Renderable;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLES11Ext;
+import android.opengl.GLES20;
+import android.opengl.Matrix;
+import android.util.Log;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.CameraStreamManager;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.DrawParameters;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ShaderHelper;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+/**
+ * Shows the camera preview as an opengl texture.
+ */
+public class CameraPreviewRenderable extends Renderable {
+    private static final String TAG = "CameraPreviewRenderable";
+    private final int TEXTURE_COORDINATE_DATA_SIZE = 2;
+    private static final float[] CAMERA_TEXTURE_DATA = {
+            0.0f, 0.0f,
+            0.0f, 1.0f,
+            1.0f, 0.0f,
+            0.0f, 1.0f,
+            1.0f, 1.0f,
+            1.0f, 0.0f
+    };
+    private static final float[] CAMERA_PREVIEW_POSITION = {0.0f, 0.0f, -3.0f};
+
+    private FloatBuffer mPositionBuffer;
+    private FloatBuffer mTextureBuffer;
+
+    private int mTextureUniformHandle;
+    private int mTextureCoordinateHandle;
+
+    protected int mCameraTextureId = -1;
+
+    private SurfaceTexture mCameraSurfaceTexture;
+    private Context mContext;
+    private CameraStreamManager mCameraStreamManager;
+    private boolean mInvertAxis;
+
+    public CameraPreviewRenderable() {
+        // Reset the model matrix to the identity and move it so the OpenGL camera is looking at it.
+        Matrix.setIdentityM(getModelMatrix(), 0);
+        Matrix.translateM(getModelMatrix(), 0,
+                CAMERA_PREVIEW_POSITION[X], CAMERA_PREVIEW_POSITION[Y], CAMERA_PREVIEW_POSITION[Z]);
+    }
+
+    public void initialiseCameraPreview(float[] cameraPreviewPositionData, boolean invertAxis, Context context) {
+        // float count / floats per vertex.
+        mVertexCount = cameraPreviewPositionData.length / POSITION_DATA_SIZE;
+
+        // Initialize the buffers.
+        mPositionBuffer = ByteBuffer.allocateDirect(cameraPreviewPositionData.length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+
+        mTextureBuffer = ByteBuffer.allocateDirect(CAMERA_TEXTURE_DATA.length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+
+        mPositionBuffer.put(cameraPreviewPositionData).position(0);
+        mTextureBuffer.put(CAMERA_TEXTURE_DATA).position(0);
+
+        final String vertexShader = ShaderHelper.getCameraPreviewVertexShader();
+        final String fragmentShader = ShaderHelper.getCameraPreviewFragmentShader();
+
+        final int vertexShaderHandle =
+                ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
+        final int fragmentShaderHandle =
+                ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
+
+        mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
+                new String[]{"a_Position", "a_TexCoordinate"});
+
+        mContext = context;
+        mInvertAxis = invertAxis;
+        connectCamera();
+    }
+
+    @Override
+    public void draw(DrawParameters drawParameters) {
+        GLES20.glUseProgram(mProgramHandle);
+
+        // Set program handles for camera preview drawing.
+        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
+        mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
+        mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture");
+        mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
+        mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
+
+        // Set the active texture unit to texture unit 0.
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+
+        // Bind the texture to this unit.
+        if (mCameraTextureId != -1) {
+            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mCameraTextureId);
+        }
+
+        // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
+        GLES20.glUniform1i(mTextureUniformHandle, 0);
+
+        // Compose the model, view, and projection matrices into a single m-v-p matrix
+        updateMvpMatrix(drawParameters.getViewMatrix(), drawParameters.getProjectionMatrix());
+
+        drawCameraPreview();
+    }
+
+    /**
+     * Draws a camera preview.
+     */
+    private void drawCameraPreview() {
+        // Pass in the position information
+        mPositionBuffer.position(0);
+        GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false,
+                0, mPositionBuffer);
+
+        GLES20.glEnableVertexAttribArray(mPositionHandle);
+
+        // Pass in the texture coordinate information
+        mTextureBuffer.position(0);
+        GLES20.glVertexAttribPointer(mTextureCoordinateHandle, TEXTURE_COORDINATE_DATA_SIZE, GLES20.GL_FLOAT, false,
+                0, mTextureBuffer);
+
+        GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
+
+        // Pass in the modelview matrix.
+        GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, getMvMatrix(), 0);
+
+        // Pass in the combined matrix.
+        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, getMvpMatrix(), 0);
+
+        // Draw the camera preview.
+        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mVertexCount);
+    }
+
+    /**
+     * Updates the texture with the latest camera data.
+     *
+     * @return the timestamp of the RGB image rendered into the texture.
+     */
+    public synchronized double updateTexture() {
+        double latestCameraFrameTimestamp = -1.0;
+        if (mCameraTextureId != -1) {
+            // Copy the camera frame from the camera to the OpenGL texture
+            mCameraSurfaceTexture.updateTexImage();
+            latestCameraFrameTimestamp = mCameraSurfaceTexture.getTimestamp();
+        }
+        return latestCameraFrameTimestamp;
+    }
+
+    /**
+     * Connects the camera to the OpenGl context
+     */
+    public void connectCamera() {
+        this.mCameraTextureId = connectCameraTexture();
+    }
+
+    public void disconnectCamera() {
+        mCameraStreamManager.onStopCameraStream();
+    }
+
+    /**
+     * Connects a texture to an Android camera
+     *
+     * @return textureId of texture with camera attached/
+     */
+    private int connectCameraTexture() {
+        if (mCameraTextureId == -1) {
+            mCameraTextureId = createEmptyTexture();
+            mCameraSurfaceTexture = new SurfaceTexture(mCameraTextureId);
+            int width = mInvertAxis ? 1080 : 1920;
+            int height = mInvertAxis ? 1920 : 1080;
+            mCameraStreamManager = new CameraStreamManager(mContext, mCameraSurfaceTexture, width, height);
+            mCameraStreamManager.onStartCameraStream();
+        }
+        return mCameraTextureId;
+    }
+
+    /**
+     * Creates an empty texture.
+     *
+     * @return textureId of empty texture.
+     */
+    public static int createEmptyTexture() {
+        final int[] textureHandle = new int[1];
+
+        GLES20.glGenTextures(1, textureHandle, 0);
+
+        if (textureHandle[0] != 0) {
+            return textureHandle[0];
+        }
+
+        return -1;
+    }
+
+    @Override
+    public void destroy() {
+        if (mCameraStreamManager != null) {
+            mCameraStreamManager.onStopCameraStream();
+            mCameraStreamManager = null;
+        }
+
+        mPositionBuffer = null;
+        mTextureBuffer = null;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/ConeRenderable.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/ConeRenderable.java
new file mode 100644
index 0000000..e0dcb6a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/ConeRenderable.java
@@ -0,0 +1,179 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.Renderable;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+
+import android.opengl.GLES20;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.Colour;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ConeModelMatrixCalculator;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.DrawParameters;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ObjImporter;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ShaderHelper;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * Object that needs to be collected by user in last test.
+ */
+public class ConeRenderable extends Renderable {
+    private static final int BYTES_PER_INT = 4;
+    public static final float[] CONE_OFFSET = new float[]{
+            0.2f, -0.1f, -1.0f}; // Offset from camera position.
+
+    private FloatBuffer mPositionBuffer;
+    private IntBuffer mIndicesBuffer;
+    private FloatBuffer mNormalsBuffer;
+    private FloatBuffer mColorBuffer;
+    private int mColorHandle;
+    private int mLightPosHandle;
+    private int mLightStrengthHandle;
+    private int mNormalHandle;
+
+    private ConeModelMatrixCalculator mModelMatrixCalculator;
+
+    public ConeRenderable(int toRotate, float[] upVector) {
+        mModelMatrixCalculator = new ConeModelMatrixCalculator(toRotate, upVector);
+    }
+
+    public void initialise(ObjImporter.ObjectData coneData) {
+        mVertexCount = coneData.getIndicesData().length;
+
+        int colourCount = mVertexCount * COLOUR_DATA_SIZE; // Vertex count * rgba
+        float[] colours = new float[colourCount];
+
+        for (int i = 0; i < colourCount; i++) {
+            int index = i % COLOUR_DATA_SIZE;
+            colours[i] = Colour.WHITE[index];
+        }
+
+        // Initialize the buffers.
+        mPositionBuffer = ByteBuffer.allocateDirect(coneData.getVertexData().length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+        mColorBuffer = ByteBuffer.allocateDirect(colours.length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+        mNormalsBuffer = ByteBuffer.allocateDirect(coneData.getNormalsData().length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+        mIndicesBuffer = ByteBuffer.allocateDirect(coneData.getIndicesData().length * BYTES_PER_INT)
+                .order(ByteOrder.nativeOrder()).asIntBuffer();
+
+        mPositionBuffer.put(coneData.getVertexData()).position(0);
+        mColorBuffer.put(colours).position(0);
+        mNormalsBuffer.put(coneData.getNormalsData()).position(0);
+        mIndicesBuffer.put(coneData.getIndicesData()).position(0);
+
+        final String vertexShader = ShaderHelper.getAugmentedRealityVertexShader();
+        final String fragmentShader = ShaderHelper.getAugmentedRealityFragmentShader();
+
+        final int vertexShaderHandle =
+                ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
+        final int fragmentShaderHandle =
+                ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
+
+        mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
+                new String[]{"a_Position", "a_Color", "a_Normal"});
+    }
+
+    @Override
+    public float[] getModelMatrix() {
+        // We want a model matrix that has camera extrinsics taken into account.
+        return mModelMatrixCalculator.getModelMatrix();
+    }
+
+    public void updateModelMatrix(float[] translation, float[] rotation, float[] lookAtPosition) {
+        mModelMatrixCalculator.updateModelMatrix(translation, rotation, lookAtPosition);
+    }
+
+    public void setDevice2IMUMatrix(float[] translation, float[] quaternion) {
+        mModelMatrixCalculator.setDevice2IMUMatrix(translation, quaternion);
+    }
+
+    public void setColorCamera2IMUMatrix(float[] translation, float[] quaternion) {
+        mModelMatrixCalculator.setColorCamera2IMUMatrix(translation, quaternion);
+    }
+
+    @Override
+    public void draw(DrawParameters drawParameters) {
+        GLES20.glUseProgram(mProgramHandle);
+
+        // Set program handles for cone drawing.
+        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
+        mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
+        mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
+        mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");
+
+        // Used to calculate shadows.
+        mLightPosHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_LightPos");
+        mLightStrengthHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_LightStrength");
+        mNormalHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Normal");
+
+        // Calculate lighting information
+        float[] lightPosInEyeSpace = drawParameters.getLight()
+                .getPositionInEyeSpace(drawParameters.getViewMatrix());
+        GLES20.glUniform3f(mLightPosHandle,
+                lightPosInEyeSpace[X], lightPosInEyeSpace[Y], lightPosInEyeSpace[Z]);
+        GLES20.glUniform1f(mLightStrengthHandle, drawParameters.getLight().getStrength());
+
+        updateMvpMatrix(drawParameters.getViewMatrix(), drawParameters.getProjectionMatrix());
+        drawCone();
+    }
+
+    private void drawCone() {
+        // Pass in the position information
+        mPositionBuffer.position(0);
+        GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false,
+                0, mPositionBuffer);
+
+        GLES20.glEnableVertexAttribArray(mPositionHandle);
+
+        // Pass in the modelview matrix.
+        GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, getMvMatrix(), 0);
+
+        // Pass in the combined matrix.
+        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, getMvpMatrix(), 0);
+
+        // Pass in the color information
+        mColorBuffer.position(0);
+        GLES20.glVertexAttribPointer(mColorHandle, COLOUR_DATA_SIZE, GLES20.GL_FLOAT, false,
+                0, mColorBuffer);
+
+        GLES20.glEnableVertexAttribArray(mColorHandle);
+
+        // Pass in the normal information
+        mNormalsBuffer.position(0);
+        GLES20.glVertexAttribPointer(mNormalHandle, NORMAL_DATA_SIZE, GLES20.GL_FLOAT, false,
+                0, mNormalsBuffer);
+
+        GLES20.glEnableVertexAttribArray(mNormalHandle);
+
+        // Draw the cone.
+        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mVertexCount);
+    }
+
+    @Override
+    public void destroy() {
+        mPositionBuffer = null;
+        mIndicesBuffer = null;
+        mNormalsBuffer = null;
+        mColorBuffer = null;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/Light.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/Light.java
new file mode 100644
index 0000000..43b1001
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/Light.java
@@ -0,0 +1,86 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.Renderable;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+
+import android.opengl.Matrix;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.DrawParameters;
+
+/**
+ * Light object for applying shadows. Not actually rendered, but we make use of matrices in
+ * Renderable class.
+ */
+public class Light extends Renderable {
+    private static final float DEFAULT_LIGHT_STRENGTH = 1.0f;
+
+    private float mStrength = DEFAULT_LIGHT_STRENGTH;
+
+    /**
+     * Used to hold the transformed position of the light in eye space (after transformation via
+     * modelview matrix)
+     */
+    private final float[] mLightPosInEyeSpace = new float[4];
+
+    /**
+     * Creates a light at the given position.
+     *
+     * @param position coordinates in open gl coordinate system.
+     */
+    public Light(float[] position) {
+        new Light(position, DEFAULT_LIGHT_STRENGTH);
+    }
+
+    public float getStrength() {
+        return mStrength;
+    }
+
+    /**
+     * Creates a light at the given position with a given strength.
+     *
+     * @param position coordinates in open gl coordinate system.
+     * @param strength strength of light.
+     */
+    public Light(float[] position, float strength) {
+        mStrength = strength;
+
+        Matrix.setIdentityM(getModelMatrix(), 0);
+        Matrix.translateM(getModelMatrix(), 0, position[X], position[Y], position[Z]);
+    }
+
+    @Override
+    public void draw(DrawParameters drawParameters) {
+        // Don't actually need to draw anything here.
+    }
+
+    public synchronized float[] getPositionInEyeSpace(float[] viewMatrix) {
+        Matrix.multiplyMV(mLightPosInEyeSpace, 0, viewMatrix, 0, getModelMatrix(), 0);
+        return mLightPosInEyeSpace;
+    }
+
+    public synchronized void updateLightPosition(float[] translation) {
+        Matrix.setIdentityM(getModelMatrix(), 0);
+        Matrix.translateM(getModelMatrix(), 0, translation[X], translation[Y], translation[Z]);
+    }
+
+    @Override
+    public void destroy() {
+        // Nothing to destroy.
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/RectangleRenderable.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/RectangleRenderable.java
new file mode 100644
index 0000000..4d59d2d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/RectangleRenderable.java
@@ -0,0 +1,150 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.Renderable;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+
+import android.opengl.GLES20;
+import android.opengl.Matrix;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.Colour;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.DrawParameters;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ShaderHelper;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+/**
+ * Rotating Rectangle for the robustness test.
+ */
+public class RectangleRenderable extends Renderable {
+    private static final int LINE_WIDTH = 8;
+    protected static final float[] RECTANGLE_POSITION = {0.0f, 0.0f, -2.99f};
+
+    private FloatBuffer mPositionBuffer;
+    private FloatBuffer mColorBuffer;
+    private int mColorHandle;
+
+    private float[] mRectanglePositionData;
+
+    public RectangleRenderable() {
+        // Reset the model matrix to the identity and move it infront of the camera preview
+        Matrix.setIdentityM(getModelMatrix(), 0);
+        Matrix.translateM(getModelMatrix(), 0,
+                RECTANGLE_POSITION[X], RECTANGLE_POSITION[Y], RECTANGLE_POSITION[Z]);
+    }
+
+    public void initialiseRectangle(float[] rectanglePositionData) {
+        mRectanglePositionData = rectanglePositionData;
+
+        // Initialize the buffers.
+        mPositionBuffer = ByteBuffer.allocateDirect(mRectanglePositionData.length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+        mPositionBuffer.put(mRectanglePositionData).position(0);
+
+        // float count / floats per vertex
+        mVertexCount = mRectanglePositionData.length / POSITION_DATA_SIZE;
+        int colourCount = mVertexCount * COLOUR_DATA_SIZE; // Vertex count * rgba
+        float[] colours = new float[colourCount];
+
+        for (int i = 0; i < colourCount; i++) {
+            int index = i % COLOUR_DATA_SIZE;
+            colours[i] = Colour.GREEN[index];
+        }
+
+        mColorBuffer = ByteBuffer.allocateDirect(colours.length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+        mColorBuffer.put(colours).position(0);
+
+        final String vertexShader = ShaderHelper.getRectangleVertexShader();
+        final String fragmentShader = ShaderHelper.getRectangleFragmentShader();
+
+        final int vertexShaderHandle =
+                ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
+        final int fragmentShaderHandle =
+                ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
+
+        mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
+                new String[]{"a_Position", "a_Color"});
+    }
+
+    @Override
+    public void draw(DrawParameters drawParameters) {
+        GLES20.glUseProgram(mProgramHandle);
+
+        // Set program handles for camera preview drawing.
+        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
+        mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
+        mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
+        mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");
+
+        updateMvpMatrix(drawParameters.getViewMatrix(), drawParameters.getProjectionMatrix());
+        drawRectangle();
+    }
+
+    private void drawRectangle() {
+        // Pass in the position information
+        mPositionBuffer.position(0);
+        GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false,
+                0, mPositionBuffer);
+
+        GLES20.glEnableVertexAttribArray(mPositionHandle);
+
+        // Pass in the modelview matrix.
+        GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, getMvMatrix(), 0);
+
+        // Pass in the combined matrix.
+        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, getMvpMatrix(), 0);
+
+        synchronized (this) {
+            // Pass in the color information
+            mColorBuffer.position(0);
+            GLES20.glVertexAttribPointer(mColorHandle, COLOUR_DATA_SIZE, GLES20.GL_FLOAT, false,
+                    0, mColorBuffer);
+
+            GLES20.glEnableVertexAttribArray(mColorHandle);
+        }
+
+        // Draw the rectangle.
+        GLES20.glLineWidth(LINE_WIDTH);
+        GLES20.glDrawArrays(GLES20.GL_LINES, 0, mVertexCount); // 2 points per line * 4 lines = 8
+    }
+
+    public void setLineColor(float[] newColor) {
+        synchronized (this) {
+            // float count / floats per vertex
+            int vertexCount = mRectanglePositionData.length / POSITION_DATA_SIZE;
+            int colourCount = vertexCount * COLOUR_DATA_SIZE; // Vertex count * rgba
+            float[] colours = new float[colourCount];
+
+            for (int i = 0; i < colourCount; i++) {
+                int index = i % COLOUR_DATA_SIZE;
+                colours[i] = newColor[index];
+            }
+
+            mColorBuffer.put(colours).position(0);
+        }
+    }
+
+    @Override
+    public void destroy() {
+        mPositionBuffer = null;
+        mColorBuffer = null;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/Renderable.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/Renderable.java
new file mode 100644
index 0000000..ad2de00
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/Renderable.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 com.android.cts.verifier.sensors.sixdof.Renderer.Renderable;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.DrawParameters;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+
+import android.opengl.Matrix;
+
+/**
+ * Base class for all Renderables
+ */
+public abstract class Renderable {
+    protected static final int BYTES_PER_FLOAT = 4;
+    protected static final int POSITION_DATA_SIZE = 3;
+    protected static final int COLOUR_DATA_SIZE = 4;
+    protected static final int NORMAL_DATA_SIZE = 3;
+
+    protected int mVertexCount;
+
+    protected int mProgramHandle;
+    protected int mPositionHandle;
+    protected int mMVPMatrixHandle;
+    protected int mMVMatrixHandle;
+
+    private float[] mModelMatrix = new float[MathsUtils.MATRIX_4X4];
+    private float[] mMvMatrix = new float[MathsUtils.MATRIX_4X4];
+    private float[] mMvpMatrix = new float[MathsUtils.MATRIX_4X4];
+
+    /**
+     * Applies the view and projection matrices and draws the Renderable.
+     *
+     * @param drawParameters parameters needed for drawing objects.
+     */
+    public abstract void draw(DrawParameters drawParameters);
+
+    public synchronized void updateMvpMatrix(float[] viewMatrix,
+                                             float[] projectionMatrix) {
+        // Compose the model, view, and projection matrices into a single mvp
+        // matrix
+        Matrix.setIdentityM(mMvMatrix, 0);
+        Matrix.setIdentityM(mMvpMatrix, 0);
+        Matrix.multiplyMM(mMvMatrix, 0, viewMatrix, 0, getModelMatrix(), 0);
+        Matrix.multiplyMM(mMvpMatrix, 0, projectionMatrix, 0, mMvMatrix, 0);
+    }
+
+    public float[] getModelMatrix() {
+        return mModelMatrix;
+    }
+
+    public void setModelMatrix(float[] modelMatrix) {
+        mModelMatrix = modelMatrix;
+    }
+
+    public float[] getMvMatrix() {
+        return mMvMatrix;
+    }
+
+    public float[] getMvpMatrix() {
+        return mMvpMatrix;
+    }
+
+    public synchronized void setRotationAngle(float newAngle) {
+        // Rotate around the Z axis. (only used in robustness test).
+        float[] translations = new float[]
+                {getModelMatrix()[12], getModelMatrix()[13],getModelMatrix()[14]};
+        synchronized (this) {
+            Matrix.setIdentityM(getModelMatrix(), 0);
+            Matrix.rotateM(getModelMatrix(), 0, newAngle, 0.0f, 0.0f, 1.0f);
+            Matrix.translateM(getModelMatrix(), 0,
+                    translations[X], translations[Y], translations[Z]);
+        }
+    }
+
+    public abstract void destroy();
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/RingRenderable.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/RingRenderable.java
new file mode 100644
index 0000000..6750343
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/Renderable/RingRenderable.java
@@ -0,0 +1,187 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer.Renderable;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.Colour;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.DrawParameters;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ObjImporter;
+import com.android.cts.verifier.sensors.sixdof.Renderer.RenderUtils.ShaderHelper;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+
+import android.opengl.GLES20;
+import android.opengl.Matrix;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * Object that needs to be collected by user in last test.
+ */
+public class RingRenderable extends Renderable {
+    private static final int BYTES_PER_INT = 4;
+
+    private FloatBuffer mPositionBuffer;
+    private IntBuffer mIndicesBuffer;
+    private FloatBuffer mNormalsBuffer;
+    private FloatBuffer mColorBuffer;
+    private int mColorHandle;
+    private int mLightPosHandle;
+    private int mLightStrengthHandle;
+    private int mNormalHandle;
+
+    public RingRenderable(float[] position, float[] rotation, float[] upVector) {
+        // Reset the model matrix to the identity.
+        Matrix.setIdentityM(getModelMatrix(), 0);
+
+        float[] overallTransformation = new float[MathsUtils.MATRIX_4X4];
+        Matrix.setIdentityM(overallTransformation, 0);
+
+        // Rotation
+        float[] rotationTransformation = new float[MathsUtils.MATRIX_4X4];
+        Matrix.setIdentityM(rotationTransformation, 0);
+        // The rotation given is relative to the position of the ring, so we have to calculate the
+        // rotation as if we where at the origin.
+        MathsUtils.setLookAtM(rotationTransformation,
+                0.0f, 0.0f, 0.0f,
+                rotation[X], rotation[Y], rotation[Z],
+                upVector[X], upVector[Y], upVector[Z]);
+
+        Matrix.multiplyMM(overallTransformation, 0, rotationTransformation, 0, overallTransformation, 0);
+
+        // Translation
+        float[] translationTransformation = new float[MathsUtils.MATRIX_4X4];
+        Matrix.setIdentityM(translationTransformation, 0);
+        Matrix.translateM(translationTransformation, 0, position[X], position[Y], position[Z]);
+
+        // Apply translation to rotation.
+        Matrix.multiplyMM(overallTransformation, 0, translationTransformation, 0, overallTransformation, 0);
+        // Apply transformation to model matrix.
+        Matrix.multiplyMM(getModelMatrix(), 0, overallTransformation, 0, getModelMatrix(), 0);
+    }
+
+    /**
+     * Initialise the ring with data from the .obj file.
+     */
+    public void initialise(ObjImporter.ObjectData ringData) {
+        mVertexCount = ringData.getIndicesData().length;
+
+        int colourCount = mVertexCount * COLOUR_DATA_SIZE; // Vertex count * rgba
+        float[] colours = new float[colourCount];
+
+        for (int i = 0; i < colourCount; i++) {
+            int index = i % COLOUR_DATA_SIZE;
+            colours[i] = Colour.YELLOW[index];
+        }
+
+        // Initialize the buffers.
+        mPositionBuffer = ByteBuffer.allocateDirect(ringData.getVertexData().length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+        mColorBuffer = ByteBuffer.allocateDirect(colours.length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+        mNormalsBuffer = ByteBuffer.allocateDirect(ringData.getNormalsData().length * BYTES_PER_FLOAT)
+                .order(ByteOrder.nativeOrder()).asFloatBuffer();
+        mIndicesBuffer = ByteBuffer.allocateDirect(ringData.getIndicesData().length * BYTES_PER_INT)
+                .order(ByteOrder.nativeOrder()).asIntBuffer();
+
+        mPositionBuffer.put(ringData.getVertexData()).position(0);
+        mColorBuffer.put(colours).position(0);
+        mNormalsBuffer.put(ringData.getNormalsData()).position(0);
+        mIndicesBuffer.put(ringData.getIndicesData()).position(0);
+
+        final String vertexShader = ShaderHelper.getAugmentedRealityVertexShader();
+        final String fragmentShader = ShaderHelper.getAugmentedRealityFragmentShader();
+
+        final int vertexShaderHandle =
+                ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
+        final int fragmentShaderHandle =
+                ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
+
+        mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
+                new String[]{"a_Position", "a_Color", "a_Normal"});
+    }
+
+    @Override
+    public void draw(DrawParameters drawParameters) {
+        GLES20.glUseProgram(mProgramHandle);
+
+        // Set program handles for camera preview drawing.
+        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
+        mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
+        mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
+        mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");
+
+        // Used to calculate shadows.
+        mLightPosHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_LightPos");
+        mLightStrengthHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_LightStrength");
+        mNormalHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Normal");
+
+        // Calculate lighting information
+        float[] lightPosInEyeSpace = drawParameters.getLight()
+                .getPositionInEyeSpace(drawParameters.getViewMatrix());
+        GLES20.glUniform3f(mLightPosHandle,
+                lightPosInEyeSpace[X], lightPosInEyeSpace[Y], lightPosInEyeSpace[Z]);
+        GLES20.glUniform1f(mLightStrengthHandle, drawParameters.getLight().getStrength());
+
+        updateMvpMatrix(drawParameters.getViewMatrix(), drawParameters.getProjectionMatrix());
+        drawRing();
+    }
+
+    private void drawRing() {
+        // Pass in the position information
+        mPositionBuffer.position(0);
+        GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false,
+                0, mPositionBuffer);
+
+        GLES20.glEnableVertexAttribArray(mPositionHandle);
+
+        // Pass in the modelview matrix.
+        GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, getMvMatrix(), 0);
+
+        // Pass in the combined matrix.
+        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, getMvpMatrix(), 0);
+
+        // Pass in the color information
+        mColorBuffer.position(0);
+        GLES20.glVertexAttribPointer(mColorHandle, COLOUR_DATA_SIZE, GLES20.GL_FLOAT, false,
+                0, mColorBuffer);
+
+        GLES20.glEnableVertexAttribArray(mColorHandle);
+
+        // Pass in the normal information
+        mNormalsBuffer.position(0);
+        GLES20.glVertexAttribPointer(mNormalHandle, NORMAL_DATA_SIZE, GLES20.GL_FLOAT, false,
+                0, mNormalsBuffer);
+
+        GLES20.glEnableVertexAttribArray(mNormalHandle);
+
+        // Draw the ring.
+        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mVertexCount);
+    }
+
+    @Override
+    public void destroy() {
+        mPositionBuffer = null;
+        mIndicesBuffer = null;
+        mNormalsBuffer = null;
+        mColorBuffer = null;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RobustnessRenderer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RobustnessRenderer.java
new file mode 100644
index 0000000..6a5f9e7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Renderer/RobustnessRenderer.java
@@ -0,0 +1,111 @@
+/*
+ * 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.verifier.sensors.sixdof.Renderer;
+
+import android.content.Context;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.Renderable.RectangleRenderable;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Renderer for the robustness test
+ */
+public class RobustnessRenderer extends BaseRenderer {
+
+    private float[] mRectanglePositionData;
+    private RectangleRenderable mRectangle;
+
+    public RobustnessRenderer(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
+        super.onSurfaceCreated(glUnused, config);
+        mRectangle = new RectangleRenderable();
+    }
+
+    @Override
+    public void onSurfaceChanged(GL10 glUnused, int width, int height) {
+        super.onSurfaceChanged(glUnused, width, height);
+        mRectangle.initialiseRectangle(mRectanglePositionData);
+        mProjectionMatrix = mFrustrumProjectionMatrix;
+    }
+
+    public void setLineColor(float[] newColor) {
+        if (mIsValid) {
+            mRectangle.setLineColor(newColor);
+        }
+    }
+
+    public void updateCurrentAngle(float newAngle) {
+        if (mIsValid) {
+            mRectangle.setRotationAngle(newAngle);
+        }
+    }
+
+    public void updateTargetAngle(float newAngle) {
+        if (mIsValid) {
+            mCameraPreview.setRotationAngle(newAngle);
+        }
+    }
+
+    @Override
+    protected void doPreRenderingSetup() {
+        // Set view matrix to one that doesn't move.
+        mViewMatrix = mOrthogonalViewMatrix;
+        // Set projection matrix to show camera preview slightly set back.
+        mProjectionMatrix = mFrustrumProjectionMatrix;
+    }
+
+    @Override
+    protected void doTestSpecificRendering() {
+        // Update the texture with the latest camera frame if there is an update pending.
+        updateCameraTexture();
+
+        mDrawParameters.update(mViewMatrix, mProjectionMatrix);
+        mRectangle.draw(mDrawParameters);
+    }
+
+    @Override
+    protected float[] getCameraCoordinates(float left, float right, float bottom, float top) {
+        // Set rectangle coordinates to be the exact same as the camera preview.
+        mRectanglePositionData = new float[]{
+                2 * left, 2 * top, 0.0f,
+                2 * left, 2 * bottom, 0.0f,
+
+                2 * left, 2 * bottom, 0.0f,
+                2 * right, 2 * bottom, 0.0f,
+
+                2 * right, 2 * bottom, 0.0f,
+                2 * right, 2 * top, 0.0f,
+
+                2 * right, 2 * top, 0.0f,
+                2 * left, 2 * top, 0.0f,
+        };
+
+        return new float[]{
+                2 * left, 2 * top, 0.0f,
+                2 * left, 2 * bottom, 0.0f,
+                2 * right, 2 * top, 0.0f,
+                2 * left, 2 * bottom, 0.0f,
+                2 * right, 2 * bottom, 0.0f,
+                2 * right, 2 * top, 0.0f,
+        };
+    }
+}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointAreaCoveredException.java
similarity index 74%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointAreaCoveredException.java
index 27a6fe2..8de7bb6 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointAreaCoveredException.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.verifier.sensors.sixdof.Utils.Exceptions;
 
-package android.server.app;
-
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
+/**
+ * Exception class for not enough area covered by waypoints.
+ */
+public class WaypointAreaCoveredException extends WaypointException {
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointDistanceException.java
similarity index 74%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointDistanceException.java
index 27a6fe2..c09d12f 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointDistanceException.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.verifier.sensors.sixdof.Utils.Exceptions;
 
-package android.server.app;
-
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
+/**
+ * Exception class for being too close to the marker waypoints.
+ */
+public class WaypointDistanceException extends WaypointException {
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointException.java
similarity index 75%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointException.java
index 27a6fe2..d1fc1d9 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointException.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.verifier.sensors.sixdof.Utils.Exceptions;
 
-package android.server.app;
-
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
+/**
+ * Generic abstract exception class used by the other exceptions.
+ */
+public abstract class WaypointException extends Exception {
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointRingNotEnteredException.java
similarity index 74%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointRingNotEnteredException.java
index 27a6fe2..855bfce 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointRingNotEnteredException.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.verifier.sensors.sixdof.Utils.Exceptions;
 
-package android.server.app;
-
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
+/**
+ * Exception class for when a ring has not been entered.
+ */
+public class WaypointRingNotEnteredException extends WaypointException {
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointStartPointException.java
similarity index 73%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointStartPointException.java
index 27a6fe2..d2664f9 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointStartPointException.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.verifier.sensors.sixdof.Utils.Exceptions;
 
-package android.server.app;
-
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
+/**
+ * Exception class for the user not going back to the initial marker.
+ */
+public class WaypointStartPointException extends WaypointException {
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Manager.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Manager.java
new file mode 100644
index 0000000..f45071c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Manager.java
@@ -0,0 +1,374 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils;
+
+import com.android.cts.verifier.sensors.sixdof.Dialogs.BaseResultsDialog;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.AccuracyListener;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.BaseUiListener;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.ComplexMovementListener;
+import com.android.cts.verifier.sensors.sixdof.Interfaces.RobustnessListener;
+import com.android.cts.verifier.sensors.sixdof.Renderer.BaseRenderer;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.ReferencePath;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.RotationData;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint;
+import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.PoseData;
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+import com.android.cts.verifier.sensors.sixdof.Utils.TestPhase.AccuracyTest;
+import com.android.cts.verifier.sensors.sixdof.Utils.TestPhase.ComplexMovementTest;
+import com.android.cts.verifier.sensors.sixdof.Utils.TestPhase.RobustnessTest;
+
+import android.content.Context;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Manages all of the tests.
+ */
+public class Manager {
+    private Lap mLap = Lap.LAP_1;
+    public static final int MAX_MARKER_NUMBER = 5;
+    private ReferencePath mReferencePath = new ReferencePath();
+    private AccuracyTest mAccuracyTest;
+    private RobustnessTest mRobustnessTest;
+    private ComplexMovementTest mComplexMovementTest;
+    private TestReport mTestReport;
+    private float mRemainingPath;
+    private long mTimeRemaining;
+
+    public enum Lap {
+        LAP_1,
+        LAP_2,
+        LAP_3,
+        LAP_4,
+    }
+
+    private ComplexMovementListener mComplexMovementListener;
+    private RobustnessListener mRobustnessListener;
+    private AccuracyListener mAccuracyListener;
+    private BaseUiListener mBaseUiListener;
+
+    /**
+     * Links the listeners to the activity.
+     *
+     * @param context reference to the activity.
+     */
+    public void setupListeners(Context context) {
+        mAccuracyListener = (AccuracyListener) context;
+        mRobustnessListener = (RobustnessListener) context;
+        mComplexMovementListener = (ComplexMovementListener) context;
+        mBaseUiListener = (BaseUiListener) context;
+    }
+
+    /**
+     * Removes the references to the activity so that the activity can be properly terminated.
+     */
+    public void stopListening() {
+        mRobustnessListener = null;
+        mAccuracyListener = null;
+        mBaseUiListener = null;
+        mComplexMovementListener = null;
+    }
+
+    public void ringEntered(Ring ring) {
+        mComplexMovementListener.onRingEntered(ring);
+    }
+
+    /**
+     * Indicated that the pose provider is ready.
+     */
+    public void onPoseProviderReady() {
+        mBaseUiListener.onPoseProviderReady();
+    }
+
+    /**
+     * Constructor for the class.
+     *
+     * @param testReport a reference to the test report to be used to record failures.
+     */
+    public Manager(TestReport testReport) {
+        mTestReport = testReport;
+    }
+
+    /**
+     * Adds the waypoint data to the appropriate path.
+     *
+     * @param coordinates   the coordinates to use for the waypoint.
+     * @param userGenerated indicates whether the data was user created or system created.
+     * @throws WaypointDistanceException    if the location is too close to another.
+     * @throws WaypointAreaCoveredException if the area covered by the user is too little.
+     * @throws WaypointStartPointException  if the location is not close enough to the start.
+     */
+    public void addPoseDataToPath(
+            float[] coordinates, boolean userGenerated)
+            throws WaypointAreaCoveredException, WaypointDistanceException,
+            WaypointStartPointException, WaypointRingNotEnteredException {
+        switch (mLap) {
+            case LAP_1:
+                try {
+                    mReferencePath.createWaypointAndAddToPath(coordinates, userGenerated, mLap);
+                } catch (WaypointStartPointException exception) {
+                    float[] initialCoords = mReferencePath.getPathMarkers().get(0).getCoordinates();
+                    String initialWaypointCoords =
+                            MathsUtils.coordinatesToString(initialCoords);
+                    String distance = String.valueOf(
+                            MathsUtils.distanceCalculationInXYZSpace(
+                                    initialCoords, coordinates));
+                    String details = "Not close enough to initial waypoint:\n"
+                            + "Distance:"
+                            + distance
+                            + "\nInitial Waypoint Coordinates: "
+                            + initialWaypointCoords
+                            + "\nAttempted placement coordinates: "
+                            + MathsUtils.coordinatesToString(coordinates);
+                    mTestReport.setFailDetails(details);
+
+                    // We still need to give the exception to UI to display message.
+                    throw exception;
+                }
+
+                if (mReferencePath.getPathMarkersSize() == MAX_MARKER_NUMBER) {
+                    mAccuracyListener.lap1Complete();
+                }
+                break;
+            case LAP_2:
+                mAccuracyTest.addWaypointDataToPath(coordinates, userGenerated, mLap);
+                break;
+            case LAP_3:
+                mRobustnessTest.addWaypointDataToPath(coordinates, userGenerated, mLap);
+                break;
+            case LAP_4:
+                mComplexMovementTest.addWaypointDataToPath(coordinates, userGenerated, mLap);
+                break;
+            default:
+                throw new AssertionError("addPoseDataToPath default: Unrecognised lap", null);
+        }
+        if (userGenerated) {
+            mBaseUiListener.onWaypointPlaced();
+        }
+    }
+
+    /**
+     * Removes the last marker from the current lap.
+     */
+    public void removeLastAddedMarker() {
+        boolean resetTest;
+        switch (mLap) {
+            case LAP_1:
+                resetTest = mReferencePath.removeLastMarker();
+                break;
+            case LAP_2:
+                resetTest = mAccuracyTest.removeLastAddedMarker();
+                break;
+            case LAP_3:
+                resetTest = mRobustnessTest.removeLastAddedMarker();
+                break;
+            case LAP_4:
+                resetTest = mComplexMovementTest.removeLastAddedMarker();
+                break;
+            default:
+                throw new AssertionError("removeLastAddedMarker default: Unrecognised lap", null);
+        }
+        if (resetTest) {
+            mAccuracyListener.onReset();
+        }
+    }
+
+    /**
+     * Initiates the accuracy test.
+     */
+    public void startAccuracyTest() {
+        mAccuracyTest = new AccuracyTest(mReferencePath, mTestReport, this);
+        mLap = Lap.LAP_2;
+    }
+
+    /**
+     * Initiates the robustness test.
+     */
+    public void startRobustnessTest() {
+        mRobustnessTest = new RobustnessTest(mReferencePath, mTestReport, this,
+                BaseRenderer.getDeviceRotation((Context) mBaseUiListener));
+        mLap = Lap.LAP_3;
+
+    }
+
+    /**
+     * Initiates the complex movement test.
+     */
+    public void startComplexMovementTest() {
+        mComplexMovementTest = new ComplexMovementTest(mReferencePath, mTestReport, this);
+        mLap = Lap.LAP_4;
+    }
+
+    /**
+     * Indicates that the accuracy test has been completed.
+     *
+     * @param passList A list to indicate whether the test passes or not.
+     */
+    public void onAccuracyTestCompleted(HashMap<BaseResultsDialog.ResultType, Boolean> passList) {
+        mBaseUiListener.onResult(new ResultObject(passList));
+    }
+
+    /**
+     * Indicates that the robustness test has been completed.
+     *
+     * @param robustnessTestResults List containing information about whether the tests failed or
+     *                              passed.
+     */
+    public void onRobustnessTestCompleted(HashMap<BaseResultsDialog.ResultType, Boolean> robustnessTestResults) {
+        ResultObject robustnessResult = new ResultObject(robustnessTestResults);
+        mBaseUiListener.onResult(robustnessResult);
+    }
+
+    /**
+     * Indicates that the complex movement test has been completed.
+     *
+     * @param complexMovementTestResults List containing information about whether the tests failed
+     *                                   or passed.
+     */
+    public void onComplexMovementTestCompleted(HashMap<BaseResultsDialog.ResultType, Boolean> complexMovementTestResults) {
+        ResultObject complexMovementResult = new ResultObject(complexMovementTestResults);
+
+        if (complexMovementResult.hasPassed()) {
+            mTestReport.setTestState(TestReport.TestStatus.PASS);
+        }
+
+        mBaseUiListener.onResult(complexMovementResult);
+    }
+
+    /**
+     * Sets the path remaining for the user to travel.
+     */
+    public void calculateRemainingPath() {
+        mRemainingPath = mReferencePath.calculatePathRemaining();
+    }
+
+    /**
+     * Uses the current rotation and location to calculate the rotation detail's. Also gives the UI
+     * information about the rotation.
+     *
+     * @param rotations   Quaternion containing the current rotation.
+     * @param translation The location the rotation occurred.
+     */
+    public void calculateRotationData(float[] rotations, float[] translation) {
+        RotationData rotationData = mRobustnessTest.getRotationData(rotations, translation);
+        if (rotationData != null) {
+            mRobustnessListener.onNewRotationData(rotationData);
+        }
+    }
+
+    /**
+     * Sets the time remaining to place a waypoint.
+     */
+    public void calculateTimeRemaining() {
+        mTimeRemaining = mRobustnessTest.getTimeRemaining();
+    }
+
+    /**
+     * Handles new pose data.
+     *
+     * @param currentPose The current pose data.
+     */
+    public void onNewPoseData(PoseData currentPose) {
+        if (mReferencePath.getCurrentPathSize() != 0) {
+            switch (mLap) {
+                case LAP_1:
+                    calculateRemainingPath();
+                    break;
+                case LAP_2:
+                    break;
+                case LAP_3:
+                    if (mRobustnessTest.getTestPathMarkersSize() > 0) {
+                        calculateTimeRemaining();
+                        calculateRotationData(currentPose.getRotationAsFloats(), currentPose.getTranslationAsFloats());
+                    }
+                    break;
+                case LAP_4:
+                    mComplexMovementTest.checkIfARingHasBeenPassed(currentPose.getTranslationAsFloats());
+                    break;
+            }
+            try {
+                addPoseDataToPath(currentPose.getTranslationAsFloats(),
+                        false);
+            } catch (WaypointException e) {
+                throw new AssertionError(
+                        "System added waypoint should not be validated", e);
+            }
+        }
+    }
+
+    /**
+     * Returns the distance remaining to travel by the user.
+     */
+    public float getRemainingPath() {
+        return mRemainingPath;
+    }
+
+    /**
+     * Returns the makers in the reference path.
+     */
+    public ArrayList<Waypoint> getReferencePathMarkers() {
+        return mReferencePath.getPathMarkers();
+    }
+
+    /**
+     * Returns the makers in the accuracy test path.
+     */
+    public ArrayList<Waypoint> getTestPathMarkers() {
+        return mAccuracyTest.getTestPathMarkers();
+    }
+
+    /**
+     * Returns the time remaining to place the marker.
+     */
+    public long getTimeRemaining() {
+        return mTimeRemaining;
+    }
+
+    /**
+     * Returns the markers in the robustness test path.
+     */
+    public ArrayList<Waypoint> getRobustnessMarker() {
+        return mRobustnessTest.getTestPathMarkers();
+    }
+
+    /**
+     * Returns the current phase of the test.
+     */
+    public Lap getLap() {
+        return mLap;
+    }
+
+    /**
+     * Returns the rings in the ComplexMovement path.
+     */
+    public ArrayList<Ring> getRings() {
+        return mComplexMovementTest.getRings();
+    }
+
+    /**
+     * Returns the makers in the ComplexMovement test path.
+     */
+    public ArrayList<Waypoint> getComplexMovementTestMarkers() {
+        return mComplexMovementTest.getTestPathMarkers();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/MathsUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/MathsUtils.java
new file mode 100644
index 0000000..ee0ab2d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/MathsUtils.java
@@ -0,0 +1,309 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils;
+
+import android.opengl.Matrix;
+import android.util.Log;
+
+import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.PoseData;
+
+import java.text.DecimalFormat;
+
+/**
+ * Contains functions that are used throughout the app.
+ */
+public class MathsUtils {
+    public static final int X = PoseData.INDEX_TRANSLATION_X;
+    public static final int Y = PoseData.INDEX_TRANSLATION_Y;
+    public static final int Z = PoseData.INDEX_TRANSLATION_Z;
+
+    public static final int MATRIX_4X4 = 16;
+    public static final int VECTOR_2D = 2;
+    public static final int VECTOR_3D = 3;
+
+    public static final int ORIENTATION_0 = 0;
+    public static final int ORIENTATION_90_ANTI_CLOCKWISE = 90;
+    public static final int ORIENTATION_180_ANTI_CLOCKWISE = 180;
+    public static final int ORIENTATION_270_ANTI_CLOCKWISE = 270;
+    public static final int ORIENTATION_360_ANTI_CLOCKWISE = 360;
+
+    /**
+     * Converts from float array in 6DoF coordinate system to a Vector3 in OpenGl coordinate
+     * system.
+     *
+     * @param location float array to convert.
+     * @return the Vector3 in OpenGL coord system.
+     */
+    public static float[] convertToOpenGlCoordinates(float[] location, int toRotate) {
+        // Have to swap Y and Z as they are different in OpenGl and 6DoF. Also invert Z.
+        float[] inDefaultOrientation = new float[]{location[X], location[Z], -location[Y]};
+
+        return rotateCoordinates(inDefaultOrientation, toRotate);
+    }
+
+    public static float[] rotateCoordinates(float[] coordinates, int toRotate) {
+        final float[] inCurrentOrientation;
+
+        switch (toRotate) {
+            case ORIENTATION_0:
+            case ORIENTATION_360_ANTI_CLOCKWISE:
+                inCurrentOrientation = coordinates;
+                break;
+            case ORIENTATION_90_ANTI_CLOCKWISE:
+                inCurrentOrientation = new float[]{coordinates[Y], -coordinates[X],
+                        coordinates[Z]};
+                break;
+            case ORIENTATION_180_ANTI_CLOCKWISE:
+                inCurrentOrientation = new float[]{coordinates[X], coordinates[Y],
+                        coordinates[Z]};
+                break;
+            case ORIENTATION_270_ANTI_CLOCKWISE:
+                inCurrentOrientation = new float[]{-coordinates[Y], coordinates[X],
+                        coordinates[Z]};
+                break;
+            default:
+                throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
+        }
+
+        return inCurrentOrientation;
+    }
+
+    /**
+     * Produce a rotation transformation that looks at a point 'center' from a point 'eye'.
+     */
+    public static void setLookAtM(float[] rm, float eyeX, float eyeY, float eyeZ,
+                                  float centerX, float centerY, float centerZ,
+                                  float upX, float upY, float upZ) {
+        // Algorithm taken from DirectX documentation.
+        // https://msdn.microsoft.com/en-us/library/bb205343.aspx
+
+        float zAxisX = eyeX - centerX;
+        float zAxisY = eyeY - centerY;
+        float zAxisZ = eyeZ - centerZ;
+
+        // Normalize zAxis
+        float rlf = 1.0f / Matrix.length(zAxisX, zAxisY, zAxisZ);
+        zAxisX *= rlf;
+        zAxisY *= rlf;
+        zAxisZ *= rlf;
+
+        // compute xAxis = up x zAxis (x means "cross product")
+        float xAxisX = upY * zAxisZ - upZ * zAxisY;
+        float xAxisY = upZ * zAxisX - upX * zAxisZ;
+        float xAxisZ = upX * zAxisY - upY * zAxisX;
+
+        // and normalize xAxis
+        float rls = 1.0f / Matrix.length(xAxisX, xAxisY, xAxisZ);
+        xAxisX *= rls;
+        xAxisY *= rls;
+        xAxisZ *= rls;
+
+        // compute yAxis = zAxis x xAxis
+        float yAxisX = zAxisY * xAxisZ - zAxisZ * xAxisY;
+        float yAxisY = zAxisZ * xAxisX - zAxisX * xAxisZ;
+        float yAxisZ = zAxisX * xAxisY - zAxisY * xAxisX;
+
+        rm[0] = xAxisX;
+        rm[1] = xAxisY;
+        rm[2] = xAxisZ;
+        rm[3] = (xAxisX * eyeX) + (xAxisY * eyeY) + (xAxisZ * eyeZ);
+
+        rm[4] = yAxisX;
+        rm[5] = yAxisY;
+        rm[6] = yAxisZ;
+        rm[7] = (yAxisX * eyeX) + (yAxisY * eyeY) + (yAxisZ * eyeZ);
+
+        rm[8] = zAxisX;
+        rm[9] = zAxisY;
+        rm[10] = zAxisZ;
+        rm[11] = (zAxisX * eyeX) + (zAxisY * eyeY) + (zAxisZ * eyeZ);
+
+        rm[12] = 0.0f;
+        rm[13] = 0.0f;
+        rm[14] = 0.0f;
+        rm[15] = 1.0f;
+    }
+
+    /**
+     * A function to convert a quaternion to quaternion Matrix. Please note that Opengl.Matrix is
+     * Column Major and so we construct the matrix in Column Major Format. - - - - | 0 4 8 12 | | 1
+     * 5 9 13 | | 2 6 10 14 | | 3 7 11 15 | - - - -
+     *
+     * @param quaternion Input quaternion with float[4]
+     * @return Quaternion Matrix of float[16]
+     */
+    public static float[] quaternionMatrixOpenGL(float[] quaternion) {
+        float[] matrix = new float[16];
+        normalizeVector(quaternion);
+
+        float x = quaternion[0];
+        float y = quaternion[1];
+        float z = quaternion[2];
+        float w = quaternion[3];
+
+        float x2 = x * x;
+        float y2 = y * y;
+        float z2 = z * z;
+        float xy = x * y;
+        float xz = x * z;
+        float yz = y * z;
+        float wx = w * x;
+        float wy = w * y;
+        float wz = w * z;
+
+        matrix[0] = 1f - 2f * (y2 + z2);
+        matrix[4] = 2f * (xy - wz);
+        matrix[8] = 2f * (xz + wy);
+        matrix[12] = 0f;
+
+        matrix[1] = 2f * (xy + wz);
+        matrix[5] = 1f - 2f * (x2 + z2);
+        matrix[9] = 2f * (yz - wx);
+        matrix[13] = 0f;
+
+        matrix[2] = 2f * (xz - wy);
+        matrix[6] = 2f * (yz + wx);
+        matrix[10] = 1f - 2f * (x2 + y2);
+        matrix[14] = 0f;
+
+        matrix[3] = 0f;
+        matrix[7] = 0f;
+        matrix[11] = 0f;
+        matrix[15] = 1f;
+
+        return matrix;
+    }
+
+    /**
+     * Calculates the dot product between two vectors.
+     *
+     * @param vector1 the first vector.
+     * @param vector2 the second vector.
+     * @return the dot product.
+     */
+    public static double dotProduct(float[] vector1, float[] vector2, int dimensions) {
+        double total = 0.0;
+        for (int i = 0; i < dimensions; i++) {
+            total += vector1[i] * vector2[i];
+        }
+        return total;
+    }
+
+    /**
+     * Creates a unit vector in the direction of an arbitrary vector. The original vector is
+     * modified in place.
+     *
+     * @param v the vector to normalize.
+     */
+    public static void normalizeVector(float[] v) {
+        float mag2 = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
+        if (Math.abs(mag2) > 0.00001f && Math.abs(mag2 - 1.0f) > 0.00001f) {
+            float mag = (float) Math.sqrt(mag2);
+            v[0] = v[0] / mag;
+            v[1] = v[1] / mag;
+            v[2] = v[2] / mag;
+            v[3] = v[3] / mag;
+        }
+    }
+
+    /**
+     * Calculates the distance between 2 points in 2D space.
+     *
+     * @param point1 the mCoordinates of the first point.
+     * @param point2 the mCoordinates of the second point.
+     * @return the distance between the 2 points.
+     */
+    public static float distanceCalculationOnXYPlane(float[] point1, float[] point2) {
+        float yDifference = point2[Y] - point1[Y];
+        float xDifference = point2[X] - point1[X];
+        return (float) Math.sqrt((yDifference * yDifference) + (xDifference * xDifference));
+    }
+
+    /**
+     * Calculates the distance between 2 points in 3D space.
+     *
+     * @param point1 the mCoordinates of the first point.
+     * @param point2 the mCoordinates of the second point.
+     * @return the distance between the 2 points.
+     */
+    public static float distanceCalculationInXYZSpace(float[] point1, float[] point2) {
+        float zDifference = point2[Z] - point1[Z];
+        float yDifference = point2[Y] - point1[Y];
+        float xDifference = point2[X] - point1[X];
+        return (float) Math.sqrt((zDifference * zDifference) + (yDifference * yDifference) +
+                (xDifference * xDifference));
+    }
+
+    /**
+     * Puts the given coordinates in a printable format.
+     *
+     * @param coordinates the mCoordinates to print.
+     * @return the mCoordinates formatted.
+     */
+    public static String coordinatesToString(float[] coordinates) {
+        DecimalFormat threeDec = new DecimalFormat("0.0");
+        String formattedCoordinates = "[";
+        for (int i = 0; i < coordinates.length; i++) {
+            formattedCoordinates += threeDec.format(coordinates[i]);
+            if (i < (coordinates.length - 1)) {
+                formattedCoordinates += ", ";
+            } else {
+                formattedCoordinates += "]";
+            }
+        }
+        return formattedCoordinates;
+    }
+
+    public static float[] getDeviceOrientationMatrix(int toRotate) {
+        float[] deviceMatrix;
+
+        switch (toRotate) {
+            case ORIENTATION_0:
+            case ORIENTATION_360_ANTI_CLOCKWISE:
+                deviceMatrix = new float[]{1.0f, 0.0f, 0.0f, 0.0f,
+                        0.0f, 1.0f, 0.0f, 0.0f,
+                        0.0f, 0.0f, 1.0f, 0.0f,
+                        0.0f, 0.0f, 0.0f, 1.0f};
+                break;
+            case ORIENTATION_90_ANTI_CLOCKWISE:
+                deviceMatrix = new float[]{
+                        0.0f, -1.0f, 0.0f, 0.0f,
+                        1.0f, 0.0f, 0.0f, 0.0f,
+                        0.0f, 0.0f, 1.0f, 0.0f,
+                        0.0f, 0.0f, 0.0f, 1.0f};
+                break;
+            case ORIENTATION_180_ANTI_CLOCKWISE:
+                deviceMatrix = new float[]{
+                        -1.0f, 0.0f, 0.0f, 0.0f,
+                        0.0f, -1.0f, 0.0f, 0.0f,
+                        0.0f, 0.0f, 1.0f, 0.0f,
+                        0.0f, 0.0f, 0.0f, 1.0f};
+                break;
+            case ORIENTATION_270_ANTI_CLOCKWISE:
+                deviceMatrix = new float[]{
+                        0.0f, 1.0f, 0.0f, 0.0f,
+                        -1.0f, 0.0f, 0.0f, 0.0f,
+                        0.0f, 0.0f, 1.0f, 0.0f,
+                        0.0f, 0.0f, 0.0f, 1.0f};
+                break;
+            default:
+                throw new RuntimeException("Unexpected orientation that cannot be dealt with!");
+        }
+
+        return deviceMatrix;
+    }
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/AccuracyPath.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/AccuracyPath.java
new file mode 100644
index 0000000..22e3bf4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/AccuracyPath.java
@@ -0,0 +1,32 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.Path;
+
+/**
+ * Class with the implementation for the Accuracy path
+ */
+public class AccuracyPath extends Path {
+    /**
+     * Implementation of the abstract class in path but left empty because there is nothing extra to
+     * check for.
+     *
+     * @param coordinates the coordinates for the waypoint
+     */
+    @Override
+    public void additionalChecks(float[] coordinates) {
+        // No additional checks required in this test.
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/ComplexMovementPath.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/ComplexMovementPath.java
new file mode 100644
index 0000000..bc7c2c4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/ComplexMovementPath.java
@@ -0,0 +1,333 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.Path;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.VECTOR_2D;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.X;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Y;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.Z;
+import static com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils.dotProduct;
+
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint;
+
+/**
+ * Handles all the path properties of the ComplexMovement Path.
+ */
+public class ComplexMovementPath extends com.android.cts.verifier.sensors.sixdof.Utils.Path.Path {
+    public static final float DISTANCE_FOR_RING_POSITION = 0.25f;
+    public static final int RINGS_PER_PATH = 5;
+
+    private ArrayList<Ring> mRings = new ArrayList<>();
+    private Random mRandomGenerator = new Random();
+    private int mCurrentLap = 0;
+    private float mLocationMapping[][];
+
+    /**
+     * Possible locations for a ring.
+     */
+    private enum RingLocations {
+        ORIGINAL,
+        TOP,
+        DOWN,
+        LEFT,
+        RIGHT,
+        TOP_LEFT,
+        TOP_RIGHT,
+        BOTTOM_LEFT,
+        BOTTOM_RIGHT,
+    }
+
+    /**
+     * Constructor for this class does the mapping and the creation of rings.
+     *
+     * @param referencePathDistances The distance between the markers in the reference path
+     * @param referencePath          The reference path
+     */
+    public ComplexMovementPath(
+            ArrayList<Float> referencePathDistances, ArrayList<Waypoint> referencePath) {
+        mapNineRingLocations();
+        generatePathRings(referencePathDistances, referencePath);
+    }
+
+    /**
+     * Defines the different ring locations that can be used when adding the rings.
+     */
+    private void mapNineRingLocations() {
+        mLocationMapping = new float[RingLocations.values().length][2];
+        mLocationMapping[RingLocations.ORIGINAL.ordinal()] = new float[]{0f, 0f};
+        mLocationMapping[RingLocations.TOP.ordinal()] =
+                new float[]{0f, DISTANCE_FOR_RING_POSITION};
+        mLocationMapping[RingLocations.DOWN.ordinal()] =
+                new float[]{0f, -DISTANCE_FOR_RING_POSITION};
+        mLocationMapping[RingLocations.LEFT.ordinal()] =
+                new float[]{-DISTANCE_FOR_RING_POSITION, 0f};
+        mLocationMapping[RingLocations.RIGHT.ordinal()] =
+                new float[]{DISTANCE_FOR_RING_POSITION, 0f};
+        mLocationMapping[RingLocations.TOP_LEFT.ordinal()] =
+                new float[]{-DISTANCE_FOR_RING_POSITION, DISTANCE_FOR_RING_POSITION};
+        mLocationMapping[RingLocations.TOP_RIGHT.ordinal()] =
+                new float[]{DISTANCE_FOR_RING_POSITION, DISTANCE_FOR_RING_POSITION};
+        mLocationMapping[RingLocations.BOTTOM_LEFT.ordinal()] =
+                new float[]{-DISTANCE_FOR_RING_POSITION, -DISTANCE_FOR_RING_POSITION};
+        mLocationMapping[RingLocations.BOTTOM_RIGHT.ordinal()] =
+                new float[]{DISTANCE_FOR_RING_POSITION, -DISTANCE_FOR_RING_POSITION};
+    }
+
+    /**
+     * Performs ComplexMovement path related checks on a marker.
+     *
+     * @param coordinates the coordinates for the waypoint
+     * @throws WaypointRingNotEnteredException if a ring is not entered
+     */
+    @Override
+    public void additionalChecks(float[] coordinates) throws WaypointRingNotEnteredException {
+        if (mCurrentLap != 0) {
+            for (Ring ring : mRings) {
+                if (ring.getPathNumber() == mCurrentLap && !ring.isEntered()) {
+                    throw new WaypointRingNotEnteredException();
+                }
+            }
+        }
+        mCurrentLap++;
+    }
+
+    /**
+     * Generates the rings for this path.
+     *
+     * @param referencePathDistances The distance between the markers in the reference path
+     * @param referencePath          The reference path
+     */
+    private void generatePathRings(
+            ArrayList<Float> referencePathDistances, ArrayList<Waypoint> referencePath) {
+        ArrayList<Float> distanceBetweenRingSections;
+        distanceBetweenRingSections = calculateSectionDistance(referencePathDistances);
+        addRingsToPath(referencePath, distanceBetweenRingSections);
+    }
+
+    /**
+     * Calculates the distance between the rings in a path.
+     *
+     * @param referencePathDistances The distance between the markers in the reference path.
+     * @return The length of a section in the different paths.
+     */
+    private ArrayList<Float> calculateSectionDistance(ArrayList<Float> referencePathDistances) {
+        ArrayList<Float> arrayToReturn = new ArrayList<>();
+        for (Float distance : referencePathDistances) {
+            arrayToReturn.add(distance / (RINGS_PER_PATH + 1f));
+        }
+        return arrayToReturn;
+    }
+
+    /**
+     * Calculates the location for the ring and adds it to the path.
+     *
+     * @param referencePath               The reference path.
+     * @param distanceBetweenRingSections The length of a section in the different paths.
+     */
+    private void addRingsToPath(
+            ArrayList<Waypoint> referencePath, ArrayList<Float> distanceBetweenRingSections) {
+        int currentPath = 0;
+        Waypoint currentWaypoint = referencePath.get(0);
+        for (Float pathIntervalDistance : distanceBetweenRingSections) {
+            currentPath++;
+            for (int i = 0; i < RINGS_PER_PATH; i++) {
+                currentWaypoint = calculateRingLocationOnPath(
+                        referencePath, referencePath.indexOf(currentWaypoint), pathIntervalDistance);
+                mRings.add(createRing(referencePath, currentWaypoint, currentPath));
+            }
+            while (!currentWaypoint.isUserGenerated()) {
+                currentWaypoint = referencePath.get(referencePath.indexOf(currentWaypoint) + 1);
+            }
+        }
+    }
+
+    /**
+     * Creates the ring that will be added onto the path.
+     *
+     * @param referencePath The reference path.
+     * @param waypoint      The waypoint which the ring will be located at.
+     * @param currentPath   The part of the lap in which the ring will be placed.
+     * @return A reference to the ring created.
+     */
+    private Ring createRing(ArrayList<Waypoint> referencePath, Waypoint waypoint, int currentPath) {
+        float[] ringCenter = waypoint.getCoordinates();
+        float[] pointRotation = calculateRingRotation(ringCenter,
+                referencePath.get(referencePath.indexOf(waypoint) - 1).getCoordinates());
+        int randomNumber = mRandomGenerator.nextInt(RingLocations.values().length);
+        RingLocations ringLocationDifference = RingLocations.values()[randomNumber];
+        ringCenter[X] += mLocationMapping[ringLocationDifference.ordinal()][0];
+        ringCenter[Z] += mLocationMapping[ringLocationDifference.ordinal()][1];
+        ArrayList<float[]> rotatedRect = calculateRectangleHitbox(ringCenter, pointRotation);
+        return new Ring(ringCenter, currentPath, pointRotation, rotatedRect);
+    }
+
+    /**
+     * Calculates the orientation of the ring.
+     *
+     * @param location1 The location of the first point.
+     * @param location2 The location of the second point.
+     * @return the rotation needed to get the orientation of the ring.
+     */
+    private float[] calculateRingRotation(float[] location1, float[] location2) {
+        float[] rotation = new float[3];
+        rotation[X] = location2[X] - location1[X];
+        rotation[Y] = location2[Y] - location1[Y];
+        rotation[Z] = location2[Z] - location1[Z];
+        return rotation;
+    }
+
+    /**
+     * Calculates the next possible position for the ring to be placed at.
+     *
+     * @param referencePath        The reference path.
+     * @param currentLocation      The location to start calculating from.
+     * @param pathIntervalDistance The distance indicating how far apart the rings are going to be.
+     * @return The waypoint where the ring will be placed at.
+     */
+    private Waypoint calculateRingLocationOnPath(
+            ArrayList<Waypoint> referencePath, int currentLocation, Float pathIntervalDistance) {
+        float pathRemaining = 0;
+        while (currentLocation < referencePath.size() - 1) {
+            pathRemaining += MathsUtils.distanceCalculationOnXYPlane(
+                    referencePath.get(currentLocation).getCoordinates(),
+                    referencePath.get(currentLocation + 1).getCoordinates());
+            if (pathRemaining >= pathIntervalDistance) {
+                return referencePath.get(currentLocation);
+            }
+            currentLocation++;
+        }
+        throw new AssertionError(
+                "calculateRingLocationOnPath: Ring number and section number don't seem to match up");
+    }
+
+    /**
+     * Calculates the rectangular hit box for the ring.
+     *
+     * @param centre   the middle location of the ring.
+     * @param rotation the rotation to get the same orientation of the ring.
+     * @return The four corners of the rectangle.
+     */
+    private ArrayList<float[]> calculateRectangleHitbox(float[] centre, float[] rotation) {
+        ArrayList<float[]> rectangle = new ArrayList<>();
+        float magnitude = (float) Math.sqrt(Math.pow(rotation[X], 2) +
+                Math.pow(rotation[Z], 2));
+        float lengthScaleFactor = 0.02f / magnitude;
+        float widthScaleFactor = 0.17f / magnitude;
+
+        float[] rotationInverse = {0 - rotation[X], 0 - rotation[Y]};
+        float[] rotationNinety = {rotation[Y], 0 - rotation[X]};
+        float[] rotationNinetyInverse = {0 - rotation[Y], rotation[X]};
+
+        float[] midFront = new float[2];
+        midFront[X] = centre[X] + (lengthScaleFactor * rotation[X]);
+        midFront[Y] = centre[Y] + (lengthScaleFactor * rotation[Y]);
+        float[] midRear = new float[2];
+        midRear[X] = centre[X] + (lengthScaleFactor * rotationInverse[X]);
+        midRear[Y] = centre[Y] + (lengthScaleFactor * rotationInverse[Y]);
+
+        float[] frontLeft = new float[3];
+        frontLeft[Z] = centre[Z];
+        frontLeft[X] = midFront[X] + (widthScaleFactor * rotationNinetyInverse[X]);
+        frontLeft[Y] = midFront[Y] + (widthScaleFactor * rotationNinetyInverse[Y]);
+        float[] frontRight = new float[3];
+        frontRight[Z] = centre[Z];
+        frontRight[X] = midFront[X] + (widthScaleFactor * rotationNinety[X]);
+        frontRight[Y] = midFront[Y] + (widthScaleFactor * rotationNinety[Y]);
+        float[] rearLeft = new float[3];
+        rearLeft[Z] = centre[Z];
+        rearLeft[X] = midRear[X] + (widthScaleFactor * rotationNinetyInverse[X]);
+        rearLeft[Y] = midRear[Y] + (widthScaleFactor * rotationNinetyInverse[Y]);
+        float[] rearRight = new float[3];
+        rearRight[Z] = centre[Z];
+        rearRight[X] = midRear[X] + (widthScaleFactor * rotationNinety[X]);
+        rearRight[Y] = midRear[Y] + (widthScaleFactor * rotationNinety[Y]);
+
+        rectangle.add(frontLeft);
+        rectangle.add(frontRight);
+        rectangle.add(rearRight);
+        rectangle.add(rearLeft);
+        return rectangle;
+    }
+
+    /**
+     * Check to see if a ring has been entered.
+     *
+     * @param location the location of the user to be tested.
+     */
+    public Ring hasRingBeenEntered(float[] location) {
+        float xDifference, yDifference, zDifference;
+        for (int i = 0; i < mRings.size(); i++) {
+            if (mRings.get(i).getPathNumber() == mCurrentLap) {
+                xDifference = Math.abs(mRings.get(i).getLocation()[X] - location[X]);
+                yDifference = Math.abs(mRings.get(i).getLocation()[Y] - location[Y]);
+                zDifference = Math.abs(mRings.get(i).getLocation()[Z] - location[Z]);
+                if (xDifference < 0.17 && yDifference < 0.17 && zDifference < 0.17) {
+                    if (checkCollision(mRings.get(i), location)) {
+                        return mRings.get(i);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Calculates whether the location of the user is in the rectangular hit box or not.
+     *
+     * @param ring     the ring to be tested.
+     * @param location the location of the user.
+     * @return true if the ring is entered and false if it is not.
+     */
+    private boolean checkCollision(Ring ring, float[] location) {
+        float[] rectangleVector1 = new float[2];
+        rectangleVector1[X] = ring.getRectangleHitBox().get(0)[X] - ring.getRectangleHitBox().get(3)[X];
+        rectangleVector1[Y] = ring.getRectangleHitBox().get(0)[Y] - ring.getRectangleHitBox().get(3)[Y];
+
+        float[] rectangleVector2 = new float[2];
+        rectangleVector2[X] = ring.getRectangleHitBox().get(2)[X] - ring.getRectangleHitBox().get(3)[X];
+        rectangleVector2[Y] = ring.getRectangleHitBox().get(2)[Y] - ring.getRectangleHitBox().get(3)[Y];
+
+        float[] locationVector = new float[2];
+        locationVector[X] = location[X] - ring.getRectangleHitBox().get(3)[X];
+        locationVector[Y] = location[Y] - ring.getRectangleHitBox().get(3)[Y];
+
+        if (dotProduct(rectangleVector1, locationVector, VECTOR_2D) > 0) {
+            if (dotProduct(rectangleVector1, rectangleVector1, VECTOR_2D)
+                    > dotProduct(rectangleVector1, locationVector, VECTOR_2D)) {
+                if (dotProduct(rectangleVector2, locationVector, VECTOR_2D) > 0) {
+                    if (dotProduct(rectangleVector2, rectangleVector2, VECTOR_2D)
+                            > dotProduct(rectangleVector2, locationVector, VECTOR_2D)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the list of rings.
+     */
+    public ArrayList<Ring> getRings() {
+        return new ArrayList<>(mRings);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/Path.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/Path.java
new file mode 100644
index 0000000..e0f21ab
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/Path.java
@@ -0,0 +1,126 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.Path;
+
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint;
+
+import java.util.ArrayList;
+
+/**
+ * Contains all the information of the current path.
+ */
+public abstract class Path {
+    protected ArrayList<Waypoint> mCurrentPath = new ArrayList<>();
+    protected ArrayList<Waypoint> mPathMarkers = new ArrayList<>();
+
+    /**
+     * Creates a waypoint and adds it to the path.
+     *
+     * @param coordinates   the coordinates to use for the waypoint.
+     * @param userGenerated indicates whether the data was user created or system created.
+     * @param currentLap    the lap the data was created in.
+     * @throws WaypointDistanceException       if the location is too close to another.
+     * @throws WaypointAreaCoveredException    if the area covered by the user is too little.
+     * @throws WaypointStartPointException     if the location is not close enough to the start.
+     * @throws WaypointRingNotEnteredException if a ring is not entered.
+     */
+    public void createWaypointAndAddToPath(
+            float[] coordinates, boolean userGenerated, Manager.Lap currentLap)
+            throws WaypointStartPointException, WaypointDistanceException,
+            WaypointAreaCoveredException, WaypointRingNotEnteredException {
+        if (userGenerated) {
+            additionalChecks(coordinates);
+        }
+        Waypoint waypoint = new Waypoint(coordinates, userGenerated, currentLap);
+        mCurrentPath.add(waypoint);
+        if (waypoint.isUserGenerated()) {
+            mPathMarkers.add(waypoint);
+        }
+    }
+
+    protected float getLengthOfCurrentPath() {
+        float length = 0.0f;
+
+        // Start at index 1.
+        for (int i = 1; i < mCurrentPath.size(); i++) {
+            float distance = MathsUtils.distanceCalculationOnXYPlane(
+                    mCurrentPath.get(i).getCoordinates(),
+                    mCurrentPath.get(i - 1).getCoordinates());
+            length += Math.abs(distance);
+        }
+
+        return length;
+    }
+
+    /**
+     * Abstract method used by classes that extend this one to run additional functionality.
+     *
+     * @param coordinates the coordinates for the waypoint.
+     * @throws WaypointDistanceException       if the location is too close to another.
+     * @throws WaypointAreaCoveredException    if the area covered by the user is too little.
+     * @throws WaypointStartPointException     if the location is not close enough to the start.
+     * @throws WaypointRingNotEnteredException if a ring is not entered.
+     */
+    public abstract void additionalChecks(float[] coordinates)
+            throws WaypointStartPointException, WaypointDistanceException,
+            WaypointAreaCoveredException, WaypointRingNotEnteredException;
+
+    /**
+     * Removes the last maker in the current path.
+     *
+     * @return true of the first marker false if any other marker.
+     */
+    public boolean removeLastMarker() {
+        Waypoint markerToRemove = mPathMarkers.get(mPathMarkers.size() - 1);
+        mCurrentPath.remove(markerToRemove);
+        mPathMarkers.remove(markerToRemove);
+        return false;
+    }
+
+    /**
+     * Returns the current path.
+     */
+    public ArrayList<Waypoint> getCurrentPath() {
+        return new ArrayList<>(mCurrentPath);
+    }
+
+    /**
+     * Returns the markers for the current path.
+     */
+    public ArrayList<Waypoint> getPathMarkers() {
+        return new ArrayList<>(mPathMarkers);
+    }
+
+    /**
+     * Returns the size of the path.
+     */
+    public int getCurrentPathSize() {
+        return mCurrentPath.size();
+    }
+
+    /**
+     * Returns the number if markers.
+     */
+    public int getPathMarkersSize() {
+        return mPathMarkers.size();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/PathUtilityClasses/Ring.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/PathUtilityClasses/Ring.java
new file mode 100644
index 0000000..636710e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/PathUtilityClasses/Ring.java
@@ -0,0 +1,120 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses;
+
+import com.android.cts.verifier.sensors.sixdof.Renderer.Renderable.RingRenderable;
+
+import java.util.ArrayList;
+
+/**
+ * Ring object, contains all the information about a ring.
+ */
+public class Ring {
+    private final float[] mLocation;
+    private final ArrayList<float[]> mRectangleHitBox;
+    private final float[] mRotation;
+    private final int mPathNumber;
+    private boolean mEntered;
+    private RingRenderable mRingRenderable;
+    private boolean mSoundPlayed = false;
+
+    /**
+     * Constructor to the ring. The ring is always initialised to not entered.
+     *
+     * @param location        the location of the center of the ring
+     * @param pathNumber      the path that the ring is located along
+     * @param rotation        the orientation of the ring
+     * @param rectangleHitBox the four corners of the rectangular hit box covered by the ring in a
+     *                        top down view
+     */
+    public Ring(float[] location, int pathNumber,
+                float[] rotation, ArrayList<float[]> rectangleHitBox) {
+        mLocation = location;
+        mEntered = false;
+        mPathNumber = pathNumber;
+        mRotation = rotation;
+        mRectangleHitBox = rectangleHitBox;
+        mSoundPlayed = false;
+    }
+
+    /**
+     * Sets whether the ring has been entered or not.
+     *
+     * @param entered true if the ring is entered, false if the ring has not been entered
+     */
+    public void setEntered(boolean entered) {
+        mEntered = entered;
+    }
+
+    /**
+     * Sets whether the sound has been played or not.
+     *
+     * @param soundPlayed the state of whether the sound has been played or not
+     */
+    public void setSoundPlayed(boolean soundPlayed) {
+        mSoundPlayed = soundPlayed;
+    }
+
+    /**
+     * Returns the location if the center of the ring.
+     */
+    public float[] getLocation() {
+        return mLocation;
+    }
+
+    /**
+     * Returns the path the ring is located along.
+     */
+    public int getPathNumber() {
+        return mPathNumber;
+    }
+
+    /**
+     * Returns the coordinates of the four corners of the rectangular hit box.
+     */
+    public ArrayList<float[]> getRectangleHitBox() {
+        return new ArrayList<>(mRectangleHitBox);
+    }
+
+    /**
+     * Returns the orientation the ring is at.
+     */
+    public float[] getRingRotation() {
+        return mRotation;
+    }
+
+    /**
+     * Returns true if the ring had been entered, false if the ring has not been entered.
+     */
+    public boolean isEntered() {
+        return mEntered;
+    }
+
+    public RingRenderable getRingRenderable() {
+        return mRingRenderable;
+    }
+
+    /**
+     * Returns true if the sound has been played, false if the sound has not been played.
+     */
+    public boolean isSoundPlayed() {
+        return mSoundPlayed;
+    }
+
+    public void setRingRenderable(RingRenderable mRingRenderable) {
+        this.mRingRenderable = mRingRenderable;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/PathUtilityClasses/RotationData.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/PathUtilityClasses/RotationData.java
new file mode 100644
index 0000000..45f080e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/PathUtilityClasses/RotationData.java
@@ -0,0 +1,75 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses;
+
+/**
+ * Contains information about a rotation.
+ */
+public class RotationData {
+    private final float mTargetRotation;
+    private final float mCurrentRotation;
+    private final boolean mRotationTestState;
+    private final float[] mLocation;
+    private final boolean mRotationState;
+
+    /**
+     * Constructor for this class.
+     *
+     * @param targetRotation    The rotation to aim for
+     * @param currentRotation   The current rotation on the device
+     * @param rotationTestState true of the currentRotation the same as the targetRotation, false if
+     *                          they are different
+     * @param location          The location the rotation was made
+     * @param rotationState     true if the rotation is testable, false if it is not
+     */
+    public RotationData(float targetRotation, float currentRotation,
+                        boolean rotationTestState, float[] location, boolean rotationState) {
+        mTargetRotation = targetRotation;
+        mCurrentRotation = currentRotation;
+        mRotationTestState = rotationTestState;
+        mLocation = location;
+        mRotationState = rotationState;
+    }
+
+    /**
+     * Returns the rotation to aim for.
+     */
+    public float getTargetAngle() {
+        return mTargetRotation;
+    }
+
+    /**
+     * Returns the current rotation of the device.
+     */
+    public float getCurrentAngle() {
+        return mCurrentRotation;
+    }
+
+    /**
+     * Returns whether the rotation passed or failed.
+     */
+    public boolean getRotationTestState() {
+        return mRotationTestState;
+    }
+
+    /**
+     * Returns whether or not the rotation is testable.
+     */
+    public boolean getRotationState() {
+        return mRotationState;
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/PathUtilityClasses/Waypoint.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/PathUtilityClasses/Waypoint.java
new file mode 100644
index 0000000..e938009
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/PathUtilityClasses/Waypoint.java
@@ -0,0 +1,61 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses;
+
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+
+/**
+ * Waypoint class used to give a waypoint a structure.
+ */
+public class Waypoint {
+    private final float[] mCoordinates;
+    private final boolean mUserGenerated;
+    private final Manager.Lap mLap;
+
+    /**
+     * Constructor for the class used to create the waypoint.
+     *
+     * @param coordinates   the location of the new waypoint
+     * @param userGenerated indicates whether it is a marker or a path point
+     * @param lap           the phase of the test the waypoint is in
+     */
+    public Waypoint(float[] coordinates, boolean userGenerated, Manager.Lap lap) {
+        this.mCoordinates = coordinates;
+        this.mUserGenerated = userGenerated;
+        this.mLap = lap;
+    }
+
+    /**
+     * Returns the mCoordinates of the waypoint.
+     */
+    public float[] getCoordinates() {
+        return mCoordinates;
+    }
+
+    /**
+     * Returns who placed the waypoint.
+     */
+    public boolean isUserGenerated() {
+        return mUserGenerated;
+    }
+
+    /**
+     * Returns the mLap the waypoint was placed on.
+     */
+    public Manager.Lap getLap() {
+        return mLap;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/ReferencePath.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/ReferencePath.java
new file mode 100644
index 0000000..57b540e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/ReferencePath.java
@@ -0,0 +1,174 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.Path;
+
+import com.android.cts.verifier.sensors.sixdof.BuildConfig;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint;
+
+/**
+ * Class that deals with reference waypoints.
+ */
+public class ReferencePath extends Path {
+    private static final float FAILURE_TOLERANCE_PERCENTAGE = 0.025f; // 2.5%
+
+    // If in Debug mode, have values that are easier to pass tests with.
+    private static final float MINIMUM_DISTANCE_FROM_WAYPOINT = (BuildConfig.DEBUG ? 0f : 3f);
+    private static final float MINIMUM_AREA_OF_TRIANGLE = (BuildConfig.DEBUG ? 0f : 2f);
+    private static final float MINIMUM_PATH_DISTANCE = (BuildConfig.DEBUG ? 0f : 10f);
+
+    private float mFailureTolerance = 0.0f;
+
+    /**
+     * @param coordinates the coordinates to use for the waypoint.
+     * @throws WaypointDistanceException    if the location is too close to another
+     * @throws WaypointAreaCoveredException if the area covered by the user is too little.
+     * @throws WaypointStartPointException  if the location is not close enough to the start.
+     */
+    @Override
+    public void additionalChecks(float[] coordinates)
+            throws WaypointStartPointException, WaypointDistanceException,
+            WaypointAreaCoveredException {
+        testValidationSelection(coordinates);
+    }
+
+    /**
+     * Checks if the marker to remove is the first marker and removes all current path details.
+     *
+     * @return true of the first marker false if any other marker
+     */
+    @Override
+    public boolean removeLastMarker() {
+        if (mPathMarkers.size() == 1) {
+            mCurrentPath.clear();
+            mPathMarkers.clear();
+            return true;
+        } else {
+            return super.removeLastMarker();
+        }
+    }
+
+    /**
+     * Calculates the path that the user still has to travel.
+     *
+     * @return The distance the user still has to travel.
+     */
+    public float calculatePathRemaining() {
+        float distance, pathRemaining = 0;
+
+        int currentLocation = mCurrentPath.indexOf(mPathMarkers.get(mPathMarkers.size() - 1));
+
+        while (currentLocation < mCurrentPath.size() - 1) {
+            distance = MathsUtils.distanceCalculationOnXYPlane(
+                    mCurrentPath.get(currentLocation).getCoordinates(),
+                    mCurrentPath.get(currentLocation + 1).getCoordinates());
+            pathRemaining += distance;
+            currentLocation++;
+        }
+        pathRemaining = MINIMUM_PATH_DISTANCE - pathRemaining;
+        return pathRemaining;
+    }
+
+    /**
+     * Executes the validation tests for the given waypoint.
+     *
+     * @param coordinates the location of the point to perform validations on.
+     * @throws WaypointDistanceException    if the location is too close to another.
+     * @throws WaypointAreaCoveredException if the area covered by the user is too little.
+     * @throws WaypointStartPointException  if the location is not close enough to the start.
+     */
+    public void testValidationSelection(float[] coordinates) throws WaypointDistanceException,
+            WaypointAreaCoveredException, WaypointStartPointException {
+        if (mPathMarkers.size() < Manager.MAX_MARKER_NUMBER - 1) {
+            validateWaypointDistance(coordinates);
+            if (mPathMarkers.size() == 2) {
+                validateAreaCovered(coordinates);
+            }
+        } else if (mPathMarkers.size() == Manager.MAX_MARKER_NUMBER - 1) {
+            validateBackToStart(coordinates);
+        }
+    }
+
+    /**
+     * Checks to make sure the waypoints added are away from other waypoints.
+     *
+     * @param coordinates the location of the point to validate the distance.
+     * @throws WaypointDistanceException WaypointDistanceException if the location is too close to
+     *                                   another.
+     */
+    private void validateWaypointDistance(float[] coordinates) throws WaypointDistanceException {
+        for (Waypoint waypoint : mPathMarkers) {
+            if (MathsUtils.distanceCalculationInXYZSpace(waypoint.getCoordinates(),
+                    coordinates) < MINIMUM_DISTANCE_FROM_WAYPOINT) {
+                throw new WaypointDistanceException();
+            }
+        }
+    }
+
+    /**
+     * Checks to make sure enough distance is covered before adding the third waypoint.
+     *
+     * @param point3 the location used to validate the area.
+     * @throws WaypointAreaCoveredException if the area covered by the user is too little.
+     */
+    private void validateAreaCovered(float[] point3) throws WaypointAreaCoveredException {
+        float[] A = mPathMarkers.get(0).getCoordinates();
+        float[] B = mPathMarkers.get(1).getCoordinates();
+
+        /* The equation used to calculate the area is:
+         * area = 1/2|(Ax - Cx)*(By - Ay) - (Ax - Bx)*(Cy - Ay) */
+        try {
+            float part1 = (A[0] - point3[0]) * (B[1] - A[1]);
+            float part2 = (A[0] - B[0]) * (point3[1] - A[1]);
+            float area = 0.5f * Math.abs((part1 - part2));
+            if (area <= MINIMUM_AREA_OF_TRIANGLE) {
+                throw new WaypointAreaCoveredException();
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw new AssertionError(
+                    "validateAreaCovered was given an array with a length less than 3", e);
+        }
+
+    }
+
+    /**
+     * Check the last waypoint of the first phase goes back to the start.
+     *
+     * @param coordinates the location of the point to validate the distance from the start marker.
+     * @throws WaypointStartPointException if the location is not close enough to the start.
+     */
+    private void validateBackToStart(float[] coordinates) throws WaypointStartPointException {
+        float[] firstMarkerCoordinates = mPathMarkers.get(0).getCoordinates();
+        float distance = MathsUtils.distanceCalculationInXYZSpace(
+                firstMarkerCoordinates, coordinates);
+
+        mFailureTolerance = FAILURE_TOLERANCE_PERCENTAGE * getLengthOfCurrentPath();
+
+        float maximumDistanceFromFirstWaypoint = (BuildConfig.DEBUG ? 1000f : mFailureTolerance);
+
+        if (distance > maximumDistanceFromFirstWaypoint) {
+            throw new WaypointStartPointException();
+        }
+    }
+
+    public float getFailureTolerance() {
+        return mFailureTolerance;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/RobustnessPath.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/RobustnessPath.java
new file mode 100644
index 0000000..f4488be
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Path/RobustnessPath.java
@@ -0,0 +1,300 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.Path;
+
+import com.android.cts.verifier.sensors.sixdof.Activities.TestActivity;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.RotationData;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint;
+
+import android.opengl.Matrix;
+import java.util.ArrayList;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Handles all the path properties of the robustness path.
+ */
+public class RobustnessPath extends Path {
+    public static final long TIME_TO_ADD_MARKER = 20000;
+    private static final int MAXIMUM_ROTATION_ANGLE = 40;
+    private static final int MINIMUM_ROTATION_ANGLE = MAXIMUM_ROTATION_ANGLE * -1;
+    private static final long TARGET_ROTATION_TIMER_INTERVALS = 100;
+    private static final float CHANGE_IN_ANGLE = 0.5f;
+    private static final int MAXIMUM_ROTATION_INACCURACY = 10;
+    private static final double DISTANCE_FROM_MARKER = 0.5F;
+
+
+    private static final float[] X_AXIS = new float[]{1, 0, 0, 0};
+
+    private float mTargetRotation = 0;
+    private boolean mRotationPhase = true;
+    private ArrayList<RotationData> mPathRotations = new ArrayList<>();
+    private ArrayList<Long> mMarkerTimeStamp = new ArrayList<>();
+    private float mDistanceOfPathFailedRotation = 0;
+
+    private int mOpenGlRotation = 0;
+
+    /**
+     * Constructor which starts the timer which changes the targetRotation.
+     */
+    public RobustnessPath(int openGlRotation) {
+        mOpenGlRotation = openGlRotation;
+        startChangingTargetRotation();
+    }
+
+    /**
+     * Performs robustness path related checks on a marker.
+     *
+     * @param coordinates the coordinates to use for the waypoint
+     * @throws WaypointDistanceException    if the location is too close to another.
+     * @throws WaypointAreaCoveredException if the area covered by the user is too little.
+     * @throws WaypointStartPointException  if the location is not close enough to the start.
+     */
+    @Override
+    public void additionalChecks(float[] coordinates)
+            throws WaypointStartPointException, WaypointDistanceException,
+            WaypointAreaCoveredException {
+        mMarkerTimeStamp.add(System.currentTimeMillis());
+        if (mPathMarkers.size() == 0) {
+            mTargetRotation = 0;
+        }
+    }
+
+    /**
+     * Starts a timer which changes the target rotation at specified intervals.
+     */
+    private void startChangingTargetRotation() {
+        Timer timer = new Timer();
+        timer.scheduleAtFixedRate(new TimerTask() {
+
+            @Override
+            public void run() {
+                synchronized (TestActivity.POSE_LOCK) {
+                    setRotationToMake();
+                }
+            }
+        }, 0, TARGET_ROTATION_TIMER_INTERVALS);
+    }
+
+    /**
+     * Performs the change to the target rotation.
+     */
+    private void setRotationToMake() {
+        if (mRotationPhase) {
+            mTargetRotation = mTargetRotation - CHANGE_IN_ANGLE;
+            if (mTargetRotation <= MINIMUM_ROTATION_ANGLE) {
+                mRotationPhase = false;
+            }
+        } else {
+            mTargetRotation = mTargetRotation + CHANGE_IN_ANGLE;
+            if (mTargetRotation >= MAXIMUM_ROTATION_ANGLE) {
+                mRotationPhase = true;
+            }
+        }
+    }
+
+    /**
+     * Calculates the time left for the user to place the waypoint.
+     *
+     * @return the time left based on the current timestamp and the timestamp of the last marker.
+     */
+    public long calculateTimeRemaining() {
+        long timeRemaining;
+        if (!mMarkerTimeStamp.isEmpty()) {
+            int lastTimestamp = mMarkerTimeStamp.size() - 1;
+            timeRemaining = System.currentTimeMillis() - mMarkerTimeStamp.get(lastTimestamp);
+            return TIME_TO_ADD_MARKER - timeRemaining;
+        }
+        return TIME_TO_ADD_MARKER;
+    }
+
+    /**
+     * Converts the rotation from quaternion to euler.
+     *
+     * @param rotationQuaternion The quaternions of the current rotation.
+     * @return The euler rotation.
+     */
+    private float calculateRotation(float[] rotationQuaternion) {
+        float qx = rotationQuaternion[0];
+        float qy = rotationQuaternion[1];
+        float qz = rotationQuaternion[2];
+        float qw = rotationQuaternion[3];
+
+        // Set initial Vector to be -(X Axis).
+        double x = -X_AXIS[0];
+        double y = X_AXIS[1];
+        double z = X_AXIS[2];
+
+        // Create quaternion based rotation matrix and extract the values that we need.
+        final double X = x * (qy * qy + qx * qx - qz * qz - qw * qw)
+                + y * (2 * qy * qz - 2 * qx * qw)
+                + z * (2 * qy * qw + 2 * qx * qz);
+        final double Y = x * (2 * qx * qw + 2 * qy * qz)
+                + y * (qx * qx - qy * qy + qz * qz - qw * qw)
+                + z * (-2 * qx * qy + 2 * qz * qw);
+        final double Z = x * (-2 * qx * qz + 2 * qy * qw)
+                + y * (2 * qx * qy + 2 * qz * qw)
+                + z * (qx * qx - qy * qy - qz * qz + qw * qw);
+
+        // Invert X and Z axis.
+        float[] values = {(float) Z, (float) Y, (float) X, 0.0f};
+        MathsUtils.normalizeVector(values);
+
+        // Rotate the X axis based on the orientation of the device.
+        float[] adjustedXAxis = new float[4];
+        Matrix.multiplyMV(adjustedXAxis, 0, MathsUtils.getDeviceOrientationMatrix(mOpenGlRotation),
+                0, X_AXIS, 0);
+
+        // Calculate angle between current pose and adjusted X axis.
+        double angle = Math.acos(MathsUtils.dotProduct(values, adjustedXAxis, MathsUtils.VECTOR_3D));
+
+        // Set our angle to be 0 based when upright.
+        angle = Math.toDegrees(angle) - MathsUtils.ORIENTATION_90_ANTI_CLOCKWISE;
+        angle *= -1;
+
+        return (float) angle;
+    }
+
+    /**
+     * Test the rotation and create a rotation object.
+     *
+     * @param rotationQuaternion    The quaternions of the current rotation.
+     * @param rotationLocation      The location of the point with the rotation.
+     * @param referencePathMarkers  The list of markers in the reference path.
+     * @param maximumDistanceToFail The distance that auto fails the test.
+     * @return The rotation data if the rotation doesn't cause the test to be invalid, null if the
+     * rotation causes the rest to be invalid.
+     */
+    public RotationData handleRotation(float[] rotationQuaternion, float[] rotationLocation,
+                                       ArrayList<Waypoint> referencePathMarkers,
+                                       float maximumDistanceToFail) {
+        float eulerRotation = calculateRotation(rotationQuaternion);
+        boolean rotationTest = testRotation(eulerRotation, rotationLocation);
+        boolean rotationTestable = checkIfRotationTestable(rotationLocation, referencePathMarkers);
+        if (mDistanceOfPathFailedRotation > maximumDistanceToFail) {
+            return null;
+        } else {
+            return createRotation(eulerRotation, rotationTest, rotationLocation, rotationTestable);
+        }
+    }
+
+    /**
+     * Tests the current rotation against the target rotation.
+     *
+     * @param eulerRotation    The rotation as a euler angle.
+     * @param rotationLocation The location of the current rotation.
+     * @return True if the rotation passes, and false if the rotation fails.
+     */
+    private boolean testRotation(double eulerRotation, float[] rotationLocation) {
+        boolean rotationTestState = true;
+        double rotationDifference = Math.abs(eulerRotation - mTargetRotation);
+        if (rotationDifference > MAXIMUM_ROTATION_INACCURACY) {
+            mDistanceOfPathFailedRotation += MathsUtils.distanceCalculationOnXYPlane(
+                    rotationLocation, mCurrentPath.get(mCurrentPath.size() - 1).getCoordinates());
+            rotationTestState = false;
+        }
+        return rotationTestState;
+    }
+
+    /**
+     * Checks to make sure the rotation not close to other markers.
+     *
+     * @param rotationLocation     The location of the point to validate the distance.
+     * @param referencePathMarkers The list of markers in the reference path.
+     * @return true if the location is not close to a marker, false if the location is close to a
+     * marker.
+     */
+    private boolean checkIfRotationTestable(
+            float[] rotationLocation, ArrayList<Waypoint> referencePathMarkers) {
+        for (Waypoint marker : referencePathMarkers) {
+            if (MathsUtils.distanceCalculationInXYZSpace(marker.getCoordinates(),
+                    rotationLocation) < DISTANCE_FROM_MARKER) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Creates a rotation data object.
+     *
+     * @param currentRotation       The rotation of the current point.
+     * @param rotationTestState     Indicates whether the rotation fails or passes the test.
+     * @param rotationLocation      The location of the current point.
+     * @param testableRotationState Indicates whether the rotation is valid for testing.
+     * @return Reference to the rotation data object which contains the rotation.
+     */
+    private RotationData createRotation(
+            float currentRotation, boolean rotationTestState, float[] rotationLocation,
+            boolean testableRotationState) {
+        RotationData rotationData = new RotationData(
+                mTargetRotation, currentRotation, rotationTestState, rotationLocation,
+                testableRotationState);
+        mPathRotations.add(rotationData);
+        return rotationData;
+    }
+
+    /**
+     * Returns the timestamps for the markers in the path.
+     */
+    public ArrayList<Long> getMarkerTimeStamp() {
+        return new ArrayList<>(mMarkerTimeStamp);
+    }
+
+    /**
+     * Returns the number of timestamps collected.
+     */
+    public int getMarkerTimeStampSize() {
+        return mMarkerTimeStamp.size();
+    }
+
+    /**
+     * Returns the rotations recorded for this path.
+     */
+    public int getRobustnessPathRotationsSize() {
+        return mPathRotations.size();
+    }
+
+    /**
+     * Returns the number of failed rotations.
+     */
+    public int getFailedRotationsSize() {
+        ArrayList<RotationData> failedRotations = new ArrayList<>();
+        for (RotationData rotationObject : mPathRotations) {
+            if (!rotationObject.getRotationTestState() && rotationObject.getRotationState()) {
+                failedRotations.add(rotationObject);
+            }
+        }
+        return failedRotations.size();
+    }
+
+    /**
+     * Returns the number of passed rotations.
+     */
+    public int getPassedRotationsSize() {
+        ArrayList<RotationData> passedRotations = new ArrayList<>();
+        for (RotationData rotationObject : mPathRotations) {
+            if (rotationObject.getRotationTestState() && rotationObject.getRotationState()) {
+                passedRotations.add(rotationObject);
+            }
+        }
+        return passedRotations.size();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/AndroidPoseProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/AndroidPoseProvider.java
new file mode 100644
index 0000000..6bf7a6d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/AndroidPoseProvider.java
@@ -0,0 +1,70 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.PoseProvider;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+/**
+ * Provides pose data using Android Sensors.
+ */
+public class AndroidPoseProvider extends PoseProvider {
+    private static final int SENSOR_TYPE_POSE = 26; //28;
+    private SensorManager mSensorManager;
+    private Sensor m6DoFSensor;
+
+    private SensorEventListener mSensorListener = new SensorEventListener() {
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            synchronized (POSE_LOCK) {
+                mLatestPoseData = new PoseData(event.values, event.timestamp);
+            }
+
+            onNewPoseData(mLatestPoseData);
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        }
+    };
+
+    public AndroidPoseProvider(Context context, PoseProviderListener poseListener) {
+        super(context, poseListener);
+        mIntrinsics = new Intrinsics();
+    }
+
+    @Override
+    public void onStartPoseProviding() {
+        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+
+        m6DoFSensor = mSensorManager.getDefaultSensor(SENSOR_TYPE_POSE);
+        mSensorManager.registerListener(mSensorListener, m6DoFSensor, SensorManager.SENSOR_DELAY_FASTEST);
+    }
+
+    @Override
+    public void onStopPoseProviding() {
+        mSensorManager.unregisterListener(mSensorListener);
+    }
+
+    @Override
+    public void setup() {
+        // Don't need to do anything here.
+        mPoseProviderListener.onSetupComplete();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/Intrinsics.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/Intrinsics.java
new file mode 100644
index 0000000..f8992c86
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/Intrinsics.java
@@ -0,0 +1,69 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.PoseProvider;
+
+/**
+ * Contains camera intrinsic information. Can be set manually or use some dummy values.
+ */
+public class Intrinsics {
+    private static final double DEFAULT_FOCAL_LENGTH = 3.5;
+    private static final double DEFAULT_SENSOR_WIDTH = 5.376;
+    private static final double DEFAULT_SENSOR_HEIGHT = 3.04;
+    /**
+     * Can any value other than 0 by default as they cancel each other out in the maths in
+     * ComplexMovementRenderer.calculateProjectionMatrix(..)
+     */
+    private static final int DEFAULT_WIDTH = 1;
+    /**
+     * Can any value other than 0 by default as they cancel each other out in the maths in
+     * ComplexMovementRenderer.calculateProjectionMatrix(..)
+     */
+    private static final int DEFAULT_HEIGHT = 1;
+
+    private int mWidth;
+    private int mHeight;
+    private double mFocalLengthInPixelsX;
+    private double mFocalLengthInPixelsY;
+
+    public Intrinsics() {
+        double focalLengthX = DEFAULT_FOCAL_LENGTH * DEFAULT_WIDTH / DEFAULT_SENSOR_WIDTH;
+        double focalLengthY = DEFAULT_FOCAL_LENGTH * DEFAULT_SENSOR_HEIGHT / DEFAULT_SENSOR_HEIGHT;
+        new Intrinsics(DEFAULT_WIDTH, DEFAULT_HEIGHT, focalLengthX, focalLengthY);
+    }
+
+    public Intrinsics(int width, int height, double focalLengthInPixelsX, double focalLengthInPixelsY) {
+        mWidth = width;
+        mHeight = height;
+        mFocalLengthInPixelsX = focalLengthInPixelsX;
+        mFocalLengthInPixelsY = focalLengthInPixelsY;
+    }
+
+    public int getWidth() {
+        return mWidth;
+    }
+
+    public int getHeight() {
+        return mHeight;
+    }
+
+    public double getFocalLengthInPixelsX() {
+        return mFocalLengthInPixelsX;
+    }
+
+    public double getFocalLengthInPixelsY() {
+        return mFocalLengthInPixelsY;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/PoseData.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/PoseData.java
new file mode 100644
index 0000000..19ba4e7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/PoseData.java
@@ -0,0 +1,106 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.PoseProvider;
+
+public class PoseData {
+    /** Index of the X-value in the translation array. */
+    public static final int INDEX_TRANSLATION_X = 0;
+    /** Index of the Y-value in the translation array. */
+    public static final int INDEX_TRANSLATION_Y = 1;
+    /** Index of the Z-value in the translation array. */
+    public static final int INDEX_TRANSLATION_Z = 2;
+
+    /** Index of the quaternion X-value in the rotation array. */
+    public static final int INDEX_ROTATION_X = 0;
+    /** Index of the quaternion Y-value in the rotation array. */
+    public static final int INDEX_ROTATION_Y = 1;
+    /** Index of the quaternion Z-value in the rotation array. */
+    public static final int INDEX_ROTATION_Z = 2;
+    /** Index of the quaternion W-value in the rotation array. */
+    public static final int INDEX_ROTATION_W = 3;
+
+    public double timestamp = 0;
+
+    /**
+     * Orientation, as a quaternion, of the pose of the target frame with reference to to the base
+     * frame.
+     * <p>
+     * Specified as (x,y,z,w) where RotationAngle is in radians:
+     * <pre>
+     * x = RotationAxis.x * sin(RotationAngle / 2)
+     * y = RotationAxis.y * sin(RotationAngle / 2)
+     * z = RotationAxis.z * sin(RotationAngle / 2)
+     * w = cos(RotationAngle / 2)
+     * </pre>
+     */
+    public float mRotation[] = {
+            0.0f, 0.0f, 0.0f, 1.0f };
+
+    /**
+     * Translation, ordered x, y, z, of the pose of the target frame relative to the reference
+     * frame.
+     */
+    public float mTranslation[] = {
+            0.0f, 0.0f, 0.0f };
+
+    public PoseData(float[] sixDoFSensorValues, long timestamp){
+        this.timestamp = timestamp;
+        mRotation[0] = sixDoFSensorValues[0];
+        mRotation[1] = sixDoFSensorValues[1];
+        mRotation[2] = sixDoFSensorValues[2];
+        mRotation[3] = sixDoFSensorValues[3];
+        mTranslation[0] = sixDoFSensorValues[4];
+        mTranslation[1] = sixDoFSensorValues[5];
+        mTranslation[2] = sixDoFSensorValues[6];
+    }
+
+    public PoseData(float[] translation, float[] rotation, long timestamp){
+        this.timestamp = timestamp;
+        mRotation[0] = rotation[0];
+        mRotation[1] = rotation[1];
+        mRotation[2] = rotation[2];
+        mRotation[3] = rotation[3];
+        mTranslation[0] = translation[0];
+        mTranslation[1] = translation[1];
+        mTranslation[2] = translation[2];
+    }
+
+    /**
+     * Convenience function to get the rotation casted as an array of floats.
+     *
+     * @return The pose rotation.
+     */
+    public float[] getRotationAsFloats() {
+        float[] out = new float[4];
+        for (int i = 0; i < 4; i++) {
+            out[i] = mRotation[i];
+        }
+        return out;
+    }
+
+    /**
+     * Convenience function to get the translation casted as an array of floats.
+     *
+     * @return The pose translation.
+     */
+    public float[] getTranslationAsFloats() {
+        float[] out = new float[3];
+        for (int i = 0; i < 3; i++) {
+            out[i] = mTranslation[i];
+        }
+        return out;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/PoseProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/PoseProvider.java
new file mode 100644
index 0000000..5ec8ed3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/PoseProvider/PoseProvider.java
@@ -0,0 +1,64 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.PoseProvider;
+
+import android.content.Context;
+
+/**
+ * Base class for objects that provide pose data to the app.
+ */
+public abstract class PoseProvider {
+    protected Context mContext;
+    protected PoseProviderListener mPoseProviderListener;
+
+    protected PoseData mLatestPoseData;
+    protected Intrinsics mIntrinsics;
+
+    public static final Object POSE_LOCK = new Object();
+
+    public interface PoseProviderListener {
+        void onSetupComplete();
+
+        void onNewPoseData(PoseData newPoseData);
+    }
+
+    public PoseProvider(Context context, PoseProviderListener listener) {
+        mContext = context;
+        mPoseProviderListener = listener;
+    }
+
+    public abstract void onStartPoseProviding();
+
+    public abstract void onStopPoseProviding();
+
+    public abstract void setup();
+
+    protected void onNewPoseData(PoseData newPoseData){
+        if (mPoseProviderListener != null) {
+            mPoseProviderListener.onNewPoseData(newPoseData);
+        }
+    }
+
+    public PoseData getLatestPoseData() {
+        synchronized (POSE_LOCK) {
+            return mLatestPoseData;
+        }
+    }
+
+    public Intrinsics getIntrinsics() {
+        return mIntrinsics;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/ReportExporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/ReportExporter.java
new file mode 100644
index 0000000..add7a47
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/ReportExporter.java
@@ -0,0 +1,109 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils;
+
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Environment;
+import android.app.AlertDialog;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Exports the xml report to a file.
+ */
+public class ReportExporter extends AsyncTask<Void, Void, String> {
+    public static final String REPORT_DIRECTORY = "6dofVerifierReports";
+    protected static final Logger LOG = Logger.getLogger(ReportExporter.class.getName());
+
+    private final Context mContext;
+    private final String mTestReport;
+
+    public ReportExporter(Context context, String report) {
+        this.mContext = context;
+        this.mTestReport = report;
+    }
+
+    @Override
+    protected String doInBackground(Void... params) {
+        if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
+            LOG.log(Level.WARNING, "External storage is not writable.");
+            return mContext.getString(R.string.no_storage);
+        }
+        byte[] contents = mTestReport.getBytes();
+        String storagePath = System.getenv("EXTERNAL_STORAGE");
+        if (storagePath.length() == 0 || storagePath.equals("")) {
+            storagePath = Environment.getExternalStorageDirectory().getPath();
+        }
+        File reportPath = new File(storagePath, REPORT_DIRECTORY);
+        reportPath.mkdirs();
+
+        String baseName = getReportBaseName();
+        File reportFile = new File(reportPath, baseName + ".zip");
+        ZipOutputStream out = null;
+        try {
+            out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(reportFile)));
+            ZipEntry entry = new ZipEntry(baseName + ".xml");
+            out.putNextEntry(entry);
+            out.write(contents);
+        } catch (IOException e) {
+            LOG.log(Level.WARNING, "I/O exception writing report to storage.", e);
+            return mContext.getString(R.string.no_storage);
+        } finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+            } catch (IOException e) {
+                LOG.log(Level.WARNING, "I/O exception closing report.", e);
+            }
+        }
+
+        return mContext.getString(R.string.report_saved, reportFile.getPath());
+    }
+
+    private String getReportBaseName() {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd-HH.mm.ss", Locale.ENGLISH);
+        String date = dateFormat.format(new Date());
+        return "6dofVerifierReport"
+                + "-" + date
+                + "-" + Build.MANUFACTURER
+                + "-" + Build.PRODUCT
+                + "-" + Build.DEVICE
+                + "-" + Build.ID;
+    }
+
+    @Override
+    protected void onPostExecute(String result) {
+        new AlertDialog.Builder(mContext)
+                .setMessage(result)
+                .setPositiveButton(android.R.string.ok, null)
+                .show();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/ResultObjects/ResultObject.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/ResultObjects/ResultObject.java
new file mode 100644
index 0000000..8944fcb
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/ResultObjects/ResultObject.java
@@ -0,0 +1,56 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.ResultObjects;
+
+import com.android.cts.verifier.sensors.sixdof.Dialogs.AccuracyResultDialog;
+import com.android.cts.verifier.sensors.sixdof.Dialogs.BaseResultsDialog;
+
+import java.util.HashMap;
+
+/**
+ * Handles the results from the tests
+ */
+public class ResultObject {
+    private HashMap<BaseResultsDialog.ResultType, Boolean> mResults;
+
+    /**
+     * Constructor for this class.
+     *
+     * @param results List to indicate whether a test has failed or passed.
+     */
+    public ResultObject(HashMap<BaseResultsDialog.ResultType, Boolean> results) {
+        mResults = results;
+    }
+
+    /**
+     * Returns true if all tests pass and false for anything else.
+     */
+    public boolean hasPassed() {
+        for (Boolean result : mResults.values()) {
+            if (!result) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns List to indicate whether a test has failed or passed.
+     */
+    public HashMap<AccuracyResultDialog.ResultType, Boolean> getResults() {
+        return new HashMap<>(mResults);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/AccuracyTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/AccuracyTest.java
new file mode 100644
index 0000000..43889b3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/AccuracyTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.TestPhase;
+
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.TestReport;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.ReferencePath;
+
+import android.util.Log;
+
+/**
+ * Class to handle accuracy test specific operations.
+ */
+public class AccuracyTest extends Test {
+    private boolean resultsGiven = false;
+
+    /**
+     * Calls the constructor of the super class.
+     *
+     * @param referencePath Reference the the reference path.
+     * @param testReport    The test report object to record the tests.
+     * @param manager       The manager to call when the test is done.
+     */
+    public AccuracyTest(ReferencePath referencePath, TestReport testReport, Manager manager) {
+        super(referencePath, testReport, manager, "Accuracy Test");
+    }
+
+    /**
+     * Accuracy test specific checks. Checks to see if the test is done.
+     */
+    @Override
+    protected void runAdditionalMethods() {
+        if (mTestPath.getPathMarkersSize() == MAX_MARKER_NUMBER && !resultsGiven) {
+            Log.e("testPhase addPoseData:", "giving the results");
+            resultsGiven = true;
+            mManager.onAccuracyTestCompleted(super.executeTests(true, true));
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/ComplexMovementTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/ComplexMovementTest.java
new file mode 100644
index 0000000..47e8927
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/ComplexMovementTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.TestPhase;
+
+import com.android.cts.verifier.sensors.sixdof.Dialogs.BaseResultsDialog;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.TestReport;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.ComplexMovementPath;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.ReferencePath;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Handles all the ComplexMovement test related features.
+ */
+public class ComplexMovementTest extends Test {
+    private boolean mResultsGiven = false;
+
+    /**
+     * Created a new ComplexMovement path which is to be used in this test.
+     *
+     * @param referencePath Reference the the reference path.
+     * @param testReport    The test report object to record the tests.
+     * @param manager       The manager to call when the test is done.
+     */
+    public ComplexMovementTest(ReferencePath referencePath, TestReport testReport, Manager manager) {
+        super(referencePath, testReport, manager, "Complex Movement Test");
+        mTestPath = new ComplexMovementPath(mReferencePathDistances, mReferencePath.getCurrentPath());
+    }
+
+    /**
+     * Implementation of the abstract method which check whether the test is complete.
+     */
+    @Override
+    protected void runAdditionalMethods() {
+        if (mTestPath.getPathMarkersSize() == MAX_MARKER_NUMBER && !mResultsGiven) {
+            mResultsGiven = true;
+            executeComplexMovementTests();
+        }
+    }
+
+    /**
+     * Starts the ComplexMovement tests.
+     */
+    private void executeComplexMovementTests() {
+        HashMap<BaseResultsDialog.ResultType, Boolean> complexMovementTestResults;
+        complexMovementTestResults = executeTests(true, false);
+        complexMovementTestResults.put(BaseResultsDialog.ResultType.RINGS, testRings());
+        mManager.onComplexMovementTestCompleted(complexMovementTestResults);
+    }
+
+    /**
+     * Tests whether the current location enters a ring.
+     *
+     * @param location the current location of the user
+     */
+    public void checkIfARingHasBeenPassed(float[] location) {
+        Ring ring = ((ComplexMovementPath) mTestPath).hasRingBeenEntered(location);
+        if (ring != null && !ring.isEntered()) {
+            // If ring has not already been entered.
+            mManager.ringEntered(ring);
+            ring.setEntered(true);
+        }
+    }
+
+    /**
+     * Finds the rings that have not been entered.
+     *
+     * @return true if all rings are entered and false if there is at least one ring not entered
+     */
+    public boolean testRings() {
+        ArrayList<Ring> testArray = ((ComplexMovementPath) mTestPath).getRings();
+        boolean state = true;
+        for (int i = 0; i < testArray.size(); i++) {
+            if (!testArray.get(i).isEntered()) {
+                recordRingTestResults(i);
+                state = false;
+            }
+        }
+        return state;
+    }
+
+    /**
+     * Forms a string for the failed ring and updates the test report with the string.
+     *
+     * @param ringIndex the index of the array the ring is in
+     */
+    private void recordRingTestResults(int ringIndex) {
+        Ring ring = ((ComplexMovementPath) mTestPath).getRings().get(ringIndex);
+        String testDetails =
+                "Ring Test: Ring was not entered. Path number: " + ring.getPathNumber() +
+                        "Ring number:" + ((ringIndex % ComplexMovementPath.RINGS_PER_PATH) + 1) + "\n";
+        Log.e("Ring Result", testDetails);
+        mTestReport.setFailDetails(testDetails);
+
+    }
+
+    /**
+     * Returns the rings in the path.
+     */
+    public ArrayList<Ring> getRings() {
+        return ((ComplexMovementPath) mTestPath).getRings();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/RobustnessTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/RobustnessTest.java
new file mode 100644
index 0000000..ae73922
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/RobustnessTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.TestPhase;
+
+
+import com.android.cts.verifier.sensors.sixdof.Dialogs.BaseResultsDialog;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+import com.android.cts.verifier.sensors.sixdof.Utils.TestReport;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.ReferencePath;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.RobustnessPath;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.RotationData;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Handles all the Robustness test related features.
+ */
+public class RobustnessTest extends Test {
+    private static final float MAXIMUM_PERCENT_ROTATION_FAILURE = 50f;
+    private boolean mResultsGiven = false;
+    private ArrayList<Long> mTimeDifferences = new ArrayList<>();
+    private float mDistanceOfPathToFail;
+
+    /**
+     * Created a new robustness path which is to be used in this test.
+     *
+     * @param referencePath Reference the the reference path.
+     * @param testReport    The test report object to record the tests.
+     * @param manager       The manager to call when the test is done.
+     */
+    public RobustnessTest(ReferencePath referencePath, TestReport testReport, Manager manager,
+                          int openGlRotation) {
+        super(referencePath, testReport, manager, "Robustness Test");
+        mTestPath = new RobustnessPath(openGlRotation);
+        float mPathTotalDistance = 0;
+        for (float distance : mReferencePathDistances) {
+            mPathTotalDistance += distance;
+        }
+        mDistanceOfPathToFail = (MAXIMUM_PERCENT_ROTATION_FAILURE / 100f) * mPathTotalDistance;
+    }
+
+    /**
+     * Implementation of the abstract method which check whether the test is complete.
+     */
+    @Override
+    protected void runAdditionalMethods() {
+        if (mTestPath.getPathMarkersSize() == MAX_MARKER_NUMBER && !mResultsGiven) {
+            mResultsGiven = true;
+            executeRobustnessTests();
+        }
+    }
+
+    /**
+     * Starts the robustness tests.
+     */
+    private void executeRobustnessTests() {
+        HashMap<BaseResultsDialog.ResultType, Boolean> robustnessTestResults;
+        robustnessTestResults = executeTests(true, true);
+        robustnessTestResults.put(BaseResultsDialog.ResultType.TIME, timerTest());
+        robustnessTestResults.put(BaseResultsDialog.ResultType.ROTATION, rotationTest());
+        mManager.onRobustnessTestCompleted(robustnessTestResults);
+    }
+
+    /**
+     * Test to check whether the waypoint was placed in the appropriate time.
+     *
+     * @return true if all waypoint times were met, fail if a waypoint was placed after the time
+     * expired
+     */
+    private boolean timerTest() {
+        calculateTimeBetweenMarkers();
+        boolean state = true;
+        for (int i = 0; i < mTimeDifferences.size(); i++) {
+            if (mTimeDifferences.get(i) > RobustnessPath.TIME_TO_ADD_MARKER) {
+                recordTimerTestResults(i);
+                state = false;
+            }
+        }
+        return state;
+    }
+
+    /**
+     * Calculates the time it took to place a waypoint.
+     */
+    private void calculateTimeBetweenMarkers() {
+        long timeDifference;
+        ArrayList<Long> markerTimeStamps = ((RobustnessPath) mTestPath).getMarkerTimeStamp();
+        for (int i = 1; i < ((RobustnessPath) mTestPath).getMarkerTimeStampSize(); i++) {
+            timeDifference = markerTimeStamps.get(i) - markerTimeStamps.get(i - 1);
+            mTimeDifferences.add(timeDifference);
+        }
+    }
+
+    /**
+     * Formats the failed times into a string to add it to the test report.
+     *
+     * @param markerLocation The marker location which failed the test. Used to get the data needed
+     *                       for the test report
+     */
+    private void recordTimerTestResults(int markerLocation) {
+        long failedTime = mTimeDifferences.get(markerLocation);
+        String markerToPlace = MathsUtils.coordinatesToString(
+                mTestPath.getPathMarkers().get(markerLocation).getCoordinates());
+        String testDetails =
+                "Timer test: Marker placement was too slow that timer expired. Target time: "
+                        + RobustnessPath.TIME_TO_ADD_MARKER / 1000 + " Completed time: " + Math.abs(failedTime) / 1000 +
+                        " Marker: " + markerLocation + " Coordinates:" + markerToPlace + "\n";
+        Log.e("Timer Result", testDetails);
+        mTestReport.setFailDetails(testDetails);
+    }
+
+    /**
+     * Test to check whether the rotation test has passed based on the percent of failed rotations.
+     *
+     * @return true if the test passes, false if the test fails
+     */
+    private boolean rotationTest() {
+        float failedRotations = ((RobustnessPath) mTestPath).getFailedRotationsSize();
+        float totalRotations = ((RobustnessPath) mTestPath).getRobustnessPathRotationsSize();
+        float percentage = (failedRotations / totalRotations) * 100;
+        if (totalRotations == 0) {
+            Log.e("rotationResult", "Total was 0");
+            return false;
+        }
+        if (percentage > MAXIMUM_PERCENT_ROTATION_FAILURE) {
+            Log.d("rotationResult", "failed");
+            recordRotationTestResults(percentage, failedRotations, totalRotations);
+            return false;
+        } else {
+            Log.d("getFailedRotationSize", "" + failedRotations);
+            Log.d("total", "" + totalRotations);
+            Log.d("rotationResult", "passed ");
+            Log.d("rotationResult", "" + percentage);
+            return true;
+        }
+    }
+
+    /**
+     * Formats the failed rotations into a string to add it to the test report.
+     *
+     * @param percentFailed   Percentage of failed rotations
+     * @param failedRotations number of failed rotations
+     * @param totalRotations  number of rotations made
+     */
+    private void recordRotationTestResults(float percentFailed, float failedRotations, float totalRotations) {
+        String testDetails =
+                "Rotation test: Rotation fails were too great. Target rotation percent: "
+                        + MAXIMUM_PERCENT_ROTATION_FAILURE + " GivenRotation percent: " + percentFailed +
+                        " Failed rotation: " + failedRotations + " Total rotations:" + totalRotations + "\n";
+        Log.e("Timer Result", testDetails);
+        mTestReport.setFailDetails(testDetails);
+    }
+
+    /**
+     * gets the result of comparing the current rotation
+     *
+     * @param rotationQuaternion The quaternions of the current rotation
+     * @param location           The location of the point with the rotation
+     * @return The rotation about the current rotation
+     */
+    public RotationData getRotationData(float[] rotationQuaternion, float[] location) {
+        RotationData rotation = ((RobustnessPath) mTestPath).handleRotation(
+                rotationQuaternion, location, mReferencePath.getPathMarkers(), mDistanceOfPathToFail);
+        if (rotation == null) {
+            if (!mResultsGiven) {
+                mResultsGiven = true;
+                HashMap<BaseResultsDialog.ResultType, Boolean> testFailed = new HashMap<>();
+                testFailed.put(BaseResultsDialog.ResultType.WAYPOINT, false);
+                testFailed.put(BaseResultsDialog.ResultType.PATH, false);
+                testFailed.put(BaseResultsDialog.ResultType.TIME, false);
+                testFailed.put(BaseResultsDialog.ResultType.ROTATION, false);
+                String testDetails = "Test terminated as it its impossible to pass the remaining rotations";
+                Log.e("Rotation test:", mDistanceOfPathToFail + "");
+                Log.e("Rotation test:", testDetails);
+                mTestReport.setFailDetails(testDetails);
+                mManager.onRobustnessTestCompleted(testFailed);
+            }
+            return null;
+        } else {
+            return rotation;
+        }
+
+    }
+
+    /**
+     * Returns the time remaining for the user to place the marker
+     */
+    public long getTimeRemaining() {
+        return ((RobustnessPath) mTestPath).calculateTimeRemaining();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/Test.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/Test.java
new file mode 100644
index 0000000..f69c2a2
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestPhase/Test.java
@@ -0,0 +1,279 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils.TestPhase;
+
+import com.android.cts.verifier.sensors.sixdof.Dialogs.BaseResultsDialog;
+import com.android.cts.verifier.sensors.sixdof.Utils.Manager;
+import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils;
+import com.android.cts.verifier.sensors.sixdof.Utils.TestReport;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.AccuracyPath;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.Path;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.ReferencePath;
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * TestPhase generic class will be inherited by the other tests.
+ */
+public abstract class Test {
+    public static final int MAX_MARKER_NUMBER = 5;
+    private static final float FAILURE_TOLERANCE_PERCENTAGE = 0.025f; // 2.5%
+    private String mTestPhaseName;
+
+    protected ArrayList<Float> mMarkerAccuracy = new ArrayList<>();
+    protected ArrayList<Float> mPathAccuracy = new ArrayList<>();
+    protected ArrayList<Float> mReferencePathDistances = new ArrayList<>();
+    private ArrayList<Float> mTestPathDistances = new ArrayList<>();
+
+    protected ReferencePath mReferencePath;
+    protected Path mTestPath;
+    protected TestReport mTestReport;
+    protected Manager mManager;
+
+    /**
+     * Constructor for this class.
+     *
+     * @param referencePath Reference the the reference path.
+     * @param testReport    The test report object to record the tests.
+     * @param manager       The manager to call when the test is done.
+     */
+    public Test(ReferencePath referencePath, TestReport testReport, Manager manager, String testPhase) {
+        if (referencePath != null) {
+            mReferencePath = referencePath;
+        } else {
+            throw new AssertionError("TestPhase received a null referencePath", null);
+        }
+        mTestPhaseName = testPhase;
+        mTestReport = testReport;
+        mManager = manager;
+        mTestPath = new AccuracyPath();
+        mReferencePathDistances = calculatePathDistance(mReferencePath.getCurrentPath(), mReferencePath.getPathMarkers());
+    }
+
+    /**
+     * Adds the current waypoint to the test path.
+     *
+     * @param coordinates   the coordinates to use for the waypoint.
+     * @param userGenerated indicates whether the data was user created or system created.
+     * @param currentLap    the lap the data was created in.
+     * @throws WaypointDistanceException    if the location is too close to another.
+     * @throws WaypointAreaCoveredException if the area covered by the user is too little.
+     * @throws WaypointStartPointException  if the location is not close enough to the start.
+     */
+    public void addWaypointDataToPath(
+            float[] coordinates, boolean userGenerated, Manager.Lap currentLap)
+            throws WaypointAreaCoveredException, WaypointDistanceException,
+            WaypointStartPointException, WaypointRingNotEnteredException {
+        mTestPath.createWaypointAndAddToPath(coordinates, userGenerated, currentLap);
+        runAdditionalMethods();
+    }
+
+    /**
+     * Abstract method that is used but subclasses.
+     */
+    protected abstract void runAdditionalMethods();
+
+    /**
+     * Removes the last marker from the chosen lap.
+     *
+     * @return true of the first marker false if any other marker
+     */
+    public boolean removeLastAddedMarker() {
+        return mTestPath.removeLastMarker();
+    }
+
+    /**
+     * Performs the tests for this test phase.
+     *
+     * @return the state of the tests, true if they pass false if they fail.
+     */
+    protected HashMap<BaseResultsDialog.ResultType, Boolean> executeTests(boolean includeMarkerTest, boolean includePathTest) {
+        HashMap<BaseResultsDialog.ResultType, Boolean> testResults = new HashMap<>();
+        if (includePathTest) {
+            testResults.put(BaseResultsDialog.ResultType.PATH, pathTest());
+        }
+        if (includeMarkerTest) {
+            testResults.put(BaseResultsDialog.ResultType.WAYPOINT, markerTest());
+        }
+        return testResults;
+    }
+
+    /**
+     * Calculates the difference between the markers of the laps and executes the marker related
+     * test.
+     *
+     * @return true if the test passes and false if the rest fails.
+     */
+    private boolean markerTest() {
+        float distance;
+        for (int i = 0; i < mReferencePath.getPathMarkersSize(); i++) {
+            distance = MathsUtils.distanceCalculationInXYZSpace(
+                    mReferencePath.getPathMarkers().get(i).getCoordinates(),
+                    mTestPath.getPathMarkers().get(i).getCoordinates());
+            mMarkerAccuracy.add(distance);
+        }
+        return markerAccuracyTest();
+    }
+
+    /**
+     * Runs a check to find any markers that have failed the test and adds them to the test report.
+     *
+     * @return true if the test passes and false if the rest fails
+     */
+    private boolean markerAccuracyTest() {
+        boolean testState = true;
+        for (float markerDifference : mMarkerAccuracy) {
+            if (markerDifference > mReferencePath.getFailureTolerance()) {
+                recordMarkerTestResults(markerDifference);
+                testState = false;
+            }
+        }
+        return testState;
+    }
+
+    /**
+     * Formats the failed markers into a string to add it to the test report.
+     *
+     * @param markerDifference the difference which caused the marker to fail
+     */
+    private void recordMarkerTestResults(float markerDifference) {
+        int markerNumber = mMarkerAccuracy.indexOf(markerDifference);
+        String referenceMarker = MathsUtils.coordinatesToString(
+                mReferencePath.getPathMarkers().get(markerNumber).getCoordinates());
+        String testMarker = MathsUtils.coordinatesToString(
+                mTestPath.getPathMarkers().get(markerNumber).getCoordinates());
+        String testDetails = mTestPhaseName +
+                " Marker Accuracy: Distance between the markers too great. Marker: " + markerNumber +
+                " Difference: " + markerDifference +
+                " Coordinates " + referenceMarker + " " + testMarker + "\n";
+        Log.e("Marker Result", testDetails);
+        mTestReport.setFailDetails(testDetails);
+    }
+
+    /**
+     * Executes the the path related tests.
+     *
+     * @return true if the test passes, false if the test fails
+     */
+    private boolean pathTest() {
+        mTestPathDistances = calculatePathDistance(mTestPath.getCurrentPath(), mTestPath.getPathMarkers());
+        calculatePathDifferences();
+        return pathAccuracyTest();
+    }
+
+    /**
+     * Calculates the distance between the markers for the given path.
+     *
+     * @param pathToCalculate The path that we want to calculate the distances for
+     * @param markers         The locations of the user generated markers in that path
+     * @return the list of distances for that path
+     */
+    protected ArrayList<Float> calculatePathDistance(ArrayList<Waypoint> pathToCalculate,
+                                                     ArrayList<Waypoint> markers) {
+        ArrayList<Float> pathDistances = new ArrayList<>();
+        float totalDistance, distance;
+        int currentLocation = pathToCalculate.indexOf(markers.get(0));
+
+        while (currentLocation < pathToCalculate.size() - 1) {
+            totalDistance = 0;
+            do {
+                distance = MathsUtils.distanceCalculationOnXYPlane(
+                        pathToCalculate.get(currentLocation).getCoordinates(),
+                        pathToCalculate.get(currentLocation + 1).getCoordinates());
+                totalDistance += distance;
+                currentLocation++;
+            } while (!pathToCalculate.get(currentLocation).isUserGenerated());
+            pathDistances.add(Math.abs(totalDistance));
+            if (currentLocation == markers.size() - 1) {
+                break;
+            }
+        }
+        return pathDistances;
+    }
+
+    /**
+     * Calculates the difference between paths on different laps.
+     */
+    private void calculatePathDifferences() {
+        float difference;
+
+        if (!mReferencePathDistances.isEmpty() && !mTestPathDistances.isEmpty()) {
+            for (int i = 0; i < mReferencePathDistances.size(); i++) {
+                difference = mReferencePathDistances.get(i) - mTestPathDistances.get(i);
+                mPathAccuracy.add(Math.abs(difference));
+            }
+        } else {
+            throw new AssertionError("calculatePathDifference has one of the arrays empty", null);
+        }
+    }
+
+    /**
+     * Checks to see if any of the path differences have failed the test and adds them to the test
+     * report.
+     *
+     * @return True if the test passes and false if there is a fail
+     */
+    private boolean pathAccuracyTest() {
+        boolean testState = true;
+        for (float path : mPathAccuracy) {
+            if (path > mReferencePath.getFailureTolerance()) {
+                recordPathTestResults(path);
+                testState = false;
+            }
+        }
+        return testState;
+    }
+
+    /**
+     * Formats the failed paths into a string to add it to the test report.
+     *
+     * @param difference The distance that failed the test
+     */
+    private void recordPathTestResults(float difference) {
+        int pathNumber = mPathAccuracy.indexOf(difference);
+        String referencePath = String.valueOf(mReferencePathDistances.get(pathNumber));
+        String testPath = String.valueOf(mTestPathDistances.get(pathNumber));
+        String testDetails = mTestPhaseName +
+                " Path Length: Path length difference was too great. Path: " + pathNumber +
+                " Difference: " + difference +
+                " Paths: " + referencePath + " " + testPath + "\n";
+        Log.e("Path Result", testDetails);
+        mTestReport.setFailDetails(testDetails);
+    }
+
+    /**
+     * Returns the makers in the test path.
+     */
+    public ArrayList<Waypoint> getTestPathMarkers() {
+        return mTestPath.getPathMarkers();
+    }
+
+    /**
+     * Returns the size of the current path.
+     */
+    public int getTestPathMarkersSize() {
+        return mTestPath.getPathMarkers().size();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestReport.java
new file mode 100644
index 0000000..aeeb8b3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/TestReport.java
@@ -0,0 +1,167 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils;
+
+import android.content.Context;
+import android.os.Build;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Handles all the XML to print to the user.
+ */
+public class TestReport {
+
+    public enum TestStatus {
+        NOT_EXECUTED,
+        EXECUTED,
+        PASS,
+        FAIL,
+    }
+
+    private static final int REPORT_VERSION = 1;
+    private static DateFormat DATE_FORMAT = new SimpleDateFormat(
+            "EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
+    private static final String TEST_RESULTS_REPORT_TAG = "test-results-report";
+    private static final String VERIFIER_INFO_TAG = "verifier-info";
+    private static final String DEVICE_INFO_TAG = "device-info";
+    private static final String BUILD_INFO_TAG = "build-info";
+    private static final String TEST_RESULTS_TAG = "test-results";
+    private static final String TEST_TAG = "test";
+    private static final String TEST_DETAILS_TAG = "details";
+    private String mTestStatus = "not-executed";
+    private Context mContext;
+    private ArrayList<String> mTestDetails = new ArrayList<>();
+
+    /**
+     * Sets the context of this test.
+     *
+     * @param context reference to the activity this test is in.
+     */
+    public TestReport(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Produces the XML for the test.
+     *
+     * @return the XML of the test to display.
+     */
+    public String getContents()
+            throws IllegalArgumentException, IllegalStateException, IOException {
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        XmlSerializer xml = Xml.newSerializer();
+
+        xml.setOutput(outputStream, "utf-8");
+        xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        xml.startDocument("utf-8", true);
+
+        xml.startTag(null, TEST_RESULTS_REPORT_TAG);
+        xml.attribute(null, "report-version", Integer.toString(REPORT_VERSION));
+        xml.attribute(null, "creation-time", DATE_FORMAT.format(new Date()));
+
+        xml.startTag(null, VERIFIER_INFO_TAG);
+        xml.attribute(null, "version-name", Version.getVersionName(mContext));
+        xml.attribute(null, "version-code", Integer.toString(Version.getVersionCode(mContext)));
+        xml.endTag(null, VERIFIER_INFO_TAG);
+
+        xml.startTag(null, DEVICE_INFO_TAG);
+        xml.startTag(null, BUILD_INFO_TAG);
+        xml.attribute(null, "board", Build.BOARD);
+        xml.attribute(null, "brand", Build.BRAND);
+        xml.attribute(null, "device", Build.DEVICE);
+        xml.attribute(null, "display", Build.DISPLAY);
+        xml.attribute(null, "fingerprint", Build.FINGERPRINT);
+        xml.attribute(null, "id", Build.ID);
+        xml.attribute(null, "model", Build.MODEL);
+        xml.attribute(null, "product", Build.PRODUCT);
+        xml.attribute(null, "release", Build.VERSION.RELEASE);
+        xml.attribute(null, "sdk", Integer.toString(Build.VERSION.SDK_INT));
+        xml.endTag(null, BUILD_INFO_TAG);
+        xml.endTag(null, DEVICE_INFO_TAG);
+
+        xml.startTag(null, TEST_RESULTS_TAG);
+        xml.startTag(null, TEST_TAG);
+        xml.attribute(null, "title", "6dof accuracy test");
+        xml.attribute(null, "class-name", "com.android.cts.verifier.sixdof.Activities.TestActivity");
+
+        if (mTestDetails.isEmpty()) {
+            xml.attribute(null, "result", mTestStatus);
+        } else {
+            setTestState(TestStatus.FAIL);
+            xml.attribute(null, "result", mTestStatus);
+            xml.startTag(null, TEST_DETAILS_TAG);
+
+            for (int i = 0; i < mTestDetails.size(); i++) {
+                xml.text(mTestDetails.get(i));
+            }
+
+            xml.endTag(null, TEST_DETAILS_TAG);
+        }
+
+        xml.endTag(null, TEST_TAG);
+        xml.endTag(null, TEST_RESULTS_TAG);
+
+        xml.endTag(null, TEST_RESULTS_REPORT_TAG);
+        xml.endDocument();
+
+        return outputStream.toString("utf-8");
+    }
+
+    /**
+     * Adds the failed results to the details.
+     *
+     * @param failedPart the failed test result.
+     */
+    public void setFailDetails(String failedPart) {
+        mTestDetails.add(failedPart);
+    }
+
+    /**
+     * Sets the status the test is currently in.
+     *
+     * @param state the status the test is in.
+     */
+    public void setTestState(TestStatus state) {
+        switch (state) {
+            case EXECUTED:
+                mTestStatus = "executed";
+                break;
+            case PASS:
+                mTestStatus = "passed";
+                break;
+            case FAIL:
+                mTestStatus = "failed";
+                break;
+            case NOT_EXECUTED:
+                mTestStatus = "not-executed";
+                break;
+            default:
+                throw new AssertionError("TestExecuted default we should not be in", null);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Version.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Version.java
new file mode 100644
index 0000000..50af74f
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Version.java
@@ -0,0 +1,64 @@
+/*
+ * 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.verifier.sensors.sixdof.Utils;
+
+/*
+ * 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.
+ */
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+/**
+ * Taken from Android CTS Verifier.
+ */
+public class Version {
+    static String getVersionName(Context context) {
+        return getVersionNameStrings(context)[0];
+    }
+
+    static int getVersionCode(Context context) {
+        return getPackageInfo(context).versionCode;
+    }
+
+    static private String[] getVersionNameStrings(Context context) {
+        return getPackageInfo(context).versionName.split(" ");
+    }
+
+    static PackageInfo getPackageInfo(Context context) {
+        try {
+            PackageManager packageManager = context.getPackageManager();
+            return packageManager.getPackageInfo(context.getPackageName(), 0);
+        } catch (NameNotFoundException e) {
+            throw new RuntimeException("Could not get find package information for "
+                    + context.getPackageName());
+        }
+    }
+}
\ No newline at end of file
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
index d7fa7a7..98a63c2 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
@@ -151,7 +151,7 @@
         helpBuilder.append("  help: show this message.\n");
         helpBuilder.append("  help all: show the complete tradefed help.\n");
         helpBuilder.append("  version: show the version.\n");
-        helpBuilder.append("  exit: gracefully exit the compatibiltiy console, waiting until all ");
+        helpBuilder.append("  exit: gracefully exit the compatibility console, waiting until all ");
         helpBuilder.append("invocations have completed.\n");
         helpBuilder.append("Run:\n");
         final String runPrompt = "  run <plan> ";
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/Abi.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/Abi.java
deleted file mode 100644
index fab990e..0000000
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/Abi.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.tradefed.testtype;
-
-import com.android.tradefed.testtype.IAbi;
-
-/**
- * A class representing an ABI.
- *
- * TODO(stuartscott): should be in TradeFed.
- */
-public class Abi implements IAbi {
-
-    private final String mName;
-    private final String mBitness;
-
-    public Abi(String name, String bitness) {
-        mName = name;
-        mBitness = bitness;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getName() {
-        return mName;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getBitness() {
-        return mBitness;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String toString() {
-        return mName;
-    }
-
-}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index e75131f..98bc29b 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -49,6 +49,7 @@
 import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.testtype.Abi;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IDeviceTest;
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
index 2ab884e..7ea5ccd 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
@@ -21,6 +21,7 @@
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.result.ITestInvocationListener;
 import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.testtype.Abi;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IRemoteTest;
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
index 24c7e3d..ecbab07 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
@@ -21,6 +21,7 @@
 import com.android.compatibility.common.tradefed.testtype.IModuleDef;
 import com.android.compatibility.common.util.AbiUtils;
 import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.Abi;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.IShardableTest;
diff --git a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
index ab7dc43..24fad97 100644
--- a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
+++ b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
@@ -36,9 +36,17 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
- * Tests that profile guided compilation succeeds regardless of whether a runtime
- * profile of the target application is present on the device.
+ * Various integration tests for dex to oat compilation, with or without profiles.
+ * When changing this test, make sure it still passes in each of the following
+ * configurations:
+ * <ul>
+ *     <li>On a 'user' build</li>
+ *     <li>On a 'userdebug' build with system property 'dalvik.vm.usejitprofiles' set to false</li>
+ *     <li>On a 'userdebug' build with system property 'dalvik.vm.usejitprofiles' set to true</li>
+ * </ul>
  */
 public class AdbRootDependentCompilationTest extends DeviceTestCase {
     private static final String TAG = AdbRootDependentCompilationTest.class.getSimpleName();
@@ -66,8 +74,6 @@
     private ITestDevice mDevice;
     private byte[] profileBytes;
     private File localProfileFile;
-    private String odexFilePath;
-    private byte[] initialOdexFileContents;
     private File apkFile;
     private boolean mIsRoot;
     private boolean mNewlyObtainedRoot;
@@ -101,20 +107,6 @@
         localProfileFile = File.createTempFile("compilationtest", "prof");
         Files.write(profileBytes, localProfileFile);
         assertTrue("empty profile", profileBytes.length > 0); // sanity check
-
-        if (mIsRoot) {
-            // ensure no profiles initially present
-            for (ProfileLocation profileLocation : ProfileLocation.values()) {
-                String clientPath = profileLocation.getPath();
-                if (mDevice.doesFileExist(clientPath)) {
-                    executeAdbCommand(0, "shell", "rm", clientPath);
-                }
-            }
-            executeCompile(/* force */ true);
-            this.odexFilePath = getOdexFilePath();
-            this.initialOdexFileContents = readFileOnClient(odexFilePath);
-            assertTrue("empty odex file", initialOdexFileContents.length > 0); // sanity check
-        }
     }
 
     @Override
@@ -128,6 +120,29 @@
         super.tearDown();
     }
 
+    /**
+     * Tests compilation using {@code -r bg-dexopt -f}.
+     */
+    public void testCompile_bgDexopt() throws Exception {
+        if (!canRunTest(EnumSet.noneOf(ProfileLocation.class))) {
+            return;
+        }
+        // Usually "interpret-only"
+        String expectedInstallFilter = checkNotNull(mDevice.getProperty("pm.dexopt.install"));
+        // Usually "speed-profile"
+        String expectedBgDexoptFilter = checkNotNull(mDevice.getProperty("pm.dexopt.bg-dexopt"));
+
+        String odexPath = getOdexFilePath();
+        assertEquals(expectedInstallFilter, getCompilerFilter(odexPath));
+
+        // Without -f, the compiler would only run if it judged the bg-dexopt filter to
+        // be "better" than the install filter. However manufacturers can change those
+        // values so we don't want to depend here on the resulting filter being better.
+        executeCompile("-r", "bg-dexopt", "-f");
+
+        assertEquals(expectedBgDexoptFilter, getCompilerFilter(odexPath));
+    }
+
     /*
      The tests below test the remaining combinations of the "ref" (reference) and
      "cur" (current) profile being available. The "cur" profile gets moved/merged
@@ -140,53 +155,31 @@
      profile_assistant, it may only be available in "ref".
      */
 
-    public void testForceCompile_noProfile() throws Exception {
-        Set<ProfileLocation> profileLocations = EnumSet.noneOf(ProfileLocation.class);
-        if (!canRunTest(profileLocations)) {
-            return;
-        }
-        compileWithProfilesAndCheckFilter(profileLocations);
-        byte[] odexFileContents = readFileOnClient(odexFilePath);
-        assertBytesEqual(initialOdexFileContents, odexFileContents);
+    public void testCompile_noProfile() throws Exception {
+        compileWithProfilesAndCheckFilter(false /* expectOdexChange */,
+                EnumSet.noneOf(ProfileLocation.class));
     }
 
-    public void testForceCompile_curProfile() throws Exception {
-        Set<ProfileLocation> profileLocations = EnumSet.of(ProfileLocation.CUR);
-        if (!canRunTest(profileLocations)) {
-            return;
+    public void testCompile_curProfile() throws Exception {
+        boolean didRun = compileWithProfilesAndCheckFilter(true  /* expectOdexChange */,
+                 EnumSet.of(ProfileLocation.CUR));
+        if (didRun) {
+            assertTrue("ref profile should have been created by the compiler",
+                    mDevice.doesFileExist(ProfileLocation.REF.getPath()));
         }
-        compileWithProfilesAndCheckFilter(profileLocations);
-        assertTrue("ref profile should have been created by the compiler",
-                mDevice.doesFileExist(ProfileLocation.REF.getPath()));
-        assertFalse("odex compiled with cur profile should differ from the initial one without",
-                Arrays.equals(initialOdexFileContents, readFileOnClient(odexFilePath)));
     }
 
-    public void testForceCompile_refProfile() throws Exception {
-        Set<ProfileLocation> profileLocations = EnumSet.of(ProfileLocation.REF);
-        if (!canRunTest(profileLocations)) {
-            return;
-        }
-        compileWithProfilesAndCheckFilter(profileLocations);
+    public void testCompile_refProfile() throws Exception {
+        compileWithProfilesAndCheckFilter(false /* expectOdexChange */,
+                 EnumSet.of(ProfileLocation.REF));
         // We assume that the compiler isn't smart enough to realize that the
         // previous odex was compiled before the ref profile was in place, even
         // though theoretically it could be.
-        byte[] odexFileContents = readFileOnClient(odexFilePath);
-        assertBytesEqual(initialOdexFileContents, odexFileContents);
     }
 
-    public void testForceCompile_curAndRefProfile() throws Exception {
-        Set<ProfileLocation> profileLocations = EnumSet.of(
-                ProfileLocation.CUR, ProfileLocation.REF);
-        if (!canRunTest(profileLocations)) {
-            return;
-        }
-        compileWithProfilesAndCheckFilter(profileLocations);
-        // We assume that the compiler isn't smart enough to realize that the
-        // previous odex was compiled before the ref profile was in place, even
-        // though theoretically it could be.
-        byte[] odexFileContents = readFileOnClient(odexFilePath);
-        assertBytesEqual(initialOdexFileContents, odexFileContents);
+    public void testCompile_curAndRefProfile() throws Exception {
+        compileWithProfilesAndCheckFilter(false /* expectOdexChange */,
+                EnumSet.of(ProfileLocation.CUR, ProfileLocation.REF));
     }
 
     private byte[] readFileOnClient(String clientPath) throws Exception {
@@ -204,29 +197,58 @@
     /**
      * Places {@link #profileBytes} in the specified locations, recompiles (without -f)
      * and checks the compiler-filter in the odex file.
+     *
+     * @return whether the test ran (as opposed to early exit)
      */
-    private void compileWithProfilesAndCheckFilter(Set<ProfileLocation> profileLocations)
+    private boolean compileWithProfilesAndCheckFilter(boolean expectOdexChange,
+            Set<ProfileLocation> profileLocations)
             throws Exception {
+        if (!canRunTest(profileLocations)) {
+            return false;
+        }
+        // ensure no profiles initially present
+        for (ProfileLocation profileLocation : ProfileLocation.values()) {
+            String clientPath = profileLocation.getPath();
+            if (mDevice.doesFileExist(clientPath)) {
+                executeAdbCommand(0, "shell", "rm", clientPath);
+            }
+        }
+        executeCompile("-m", "speed-profile", "-f");
+        String odexFilePath = getOdexFilePath();
+        byte[] initialOdexFileContents = readFileOnClient(odexFilePath);
+        assertTrue("empty odex file", initialOdexFileContents.length > 0); // sanity check
+
         for (ProfileLocation profileLocation : profileLocations) {
             writeProfile(profileLocation);
         }
-        executeCompile(/* force */ false);
+        executeCompile("-m", "speed-profile");
 
         // Confirm the compiler-filter used in creating the odex file
         String compilerFilter = getCompilerFilter(odexFilePath);
 
         assertEquals("compiler-filter", "speed-profile", compilerFilter);
+
+        byte[] odexFileContents = readFileOnClient(odexFilePath);
+        boolean odexChanged = !(Arrays.equals(initialOdexFileContents, odexFileContents));
+        if (odexChanged && !expectOdexChange) {
+            String msg = String.format(Locale.US, "Odex file without filters (%d bytes) "
+                    + "unexpectedly different from odex file (%d bytes) compiled with filters: %s",
+                    initialOdexFileContents.length, odexFileContents.length, profileLocations);
+            fail(msg);
+        } else if (!odexChanged && expectOdexChange) {
+            fail("odex file should have changed when recompiling with " + profileLocations);
+        }
+        return true;
     }
 
     /**
      * Invokes the dex2oat compiler on the client.
+     *
+     * @param compileOptions extra options to pass to the compiler on the command line
      */
-    private void executeCompile(boolean force) throws Exception {
-        List<String> command = new ArrayList<>(Arrays.asList("shell", "cmd", "package", "compile",
-                "-m", "speed-profile"));
-        if (force) {
-            command.add("-f");
-        }
+    private void executeCompile(String... compileOptions) throws Exception {
+        List<String> command = new ArrayList<>(Arrays.asList("shell", "cmd", "package", "compile"));
+        command.addAll(Arrays.asList(compileOptions));
         command.add(APPLICATION_PACKAGE);
         String[] commandArray = command.toArray(new String[0]);
         assertEquals("Success", executeAdbCommand(1, commandArray)[0]);
@@ -292,8 +314,8 @@
     }
 
     /**
-     * Returns whether a test can run in the current device configuration
-     * and for the given profileLocations. This allows tests to exit early.
+     * Returns whether a test that uses the given profileLocations can run
+     * in the current device configuration. This allows tests to exit early.
      *
      * <p>Ideally we'd like tests to be marked as skipped/ignored or similar
      * rather than passing if they can't run on the current device, but that
@@ -332,10 +354,4 @@
         String[] lines = output.equals("") ? new String[0] : output.split("\n");
         return lines;
     }
-
-    private static void assertBytesEqual(byte[] expected, byte[] actual) {
-        String msg = String.format("Expected %d bytes differ from actual %d bytes",
-                expected.length, actual.length);
-        assertTrue(msg, Arrays.equals(expected, actual));
-    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
index b1c35aa..5d32955 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctsdeviceutil ctstestrunner ub-uiautomator
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := test_current
 
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
 
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
index 7d08bc3..884bb0b 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctsdeviceutil ctstestrunner ub-uiautomator
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := test_current
 
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../res
 
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
index 744db8f..1c9d24d 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
@@ -25,7 +25,8 @@
     <uses-permission android:name="android.permission.SET_WALLPAPER" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
 
-    <application
+    <!-- Add a network security config that trusts user added CAs for tests -->
+    <application android:networkSecurityConfig="@xml/network_security_config"
         android:testOnly="true">
 
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/res/xml/network_security_config.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/xml/network_security_config.xml
similarity index 100%
rename from hostsidetests/devicepolicy/app/DeviceOwner/res/xml/network_security_config.xml
rename to hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/xml/network_security_config.xml
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 34566a1..01a5a3a 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
@@ -17,6 +17,7 @@
 package com.android.cts.deviceandprofileowner;
 
 import android.os.Bundle;
+import android.os.UserManager;
 
 import com.android.cts.deviceandprofileowner.vpn.VpnTestHelper;
 
@@ -63,6 +64,18 @@
         VpnTestHelper.checkPing(TEST_ADDRESS);
     }
 
+    public void testDisallowConfigVpn() throws Exception {
+        mDevicePolicyManager.addUserRestriction(
+                ADMIN_RECEIVER_COMPONENT, UserManager.DISALLOW_CONFIG_VPN);
+        try {
+            testAlwaysOnVpn();
+        } finally {
+            // clear the user restriction
+            mDevicePolicyManager.clearUserRestriction(ADMIN_RECEIVER_COMPONENT,
+                    UserManager.DISALLOW_CONFIG_VPN);
+        }
+    }
+
     public void testAllowedApps() throws Exception {
         final Bundle restrictions = new Bundle();
         restrictions.putStringArray(RESTRICTION_ALLOWED, new String[] {mPackageName});
@@ -97,4 +110,3 @@
         assertNull(mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT));
     }
 }
-
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
similarity index 83%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
rename to hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
index 3e692c3..54222035 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.deviceowner;
+package com.android.cts.deviceandprofileowner;
 
+import android.content.ComponentName;
 import android.net.http.X509TrustManagerExtensions;
-import android.security.NetworkSecurityPolicy;
 
 import java.io.ByteArrayInputStream;
 import java.security.GeneralSecurityException;
@@ -32,17 +32,19 @@
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import static com.android.cts.deviceowner.FakeKeys.FAKE_DSA_1;
-import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
+import static android.cts.util.FakeKeys.FAKE_DSA_1;
+import static android.cts.util.FakeKeys.FAKE_RSA_1;
 
-public class CaCertManagementTest extends BaseDeviceOwnerTest {
+public class CaCertManagementTest extends BaseDeviceAdminTest {
+    private final ComponentName mAdmin = ADMIN_RECEIVER_COMPONENT;
+
     /**
      * Test: device admins should be able to list all installed certs.
      *
      * <p>The list of certificates must never be {@code null}.
      */
     public void testCanRetrieveListOfInstalledCaCerts() {
-        List<byte[]> caCerts = mDevicePolicyManager.getInstalledCaCerts(getWho());
+        List<byte[]> caCerts = mDevicePolicyManager.getInstalledCaCerts(mAdmin);
         assertNotNull(caCerts);
     }
 
@@ -54,11 +56,11 @@
         assertUninstalled(FAKE_RSA_1.caCertificate);
         assertUninstalled(FAKE_DSA_1.caCertificate);
 
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_RSA_1.caCertificate));
         assertInstalled(FAKE_RSA_1.caCertificate);
         assertUninstalled(FAKE_DSA_1.caCertificate);
 
-        mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
+        mDevicePolicyManager.uninstallCaCert(mAdmin, FAKE_RSA_1.caCertificate);
         assertUninstalled(FAKE_RSA_1.caCertificate);
         assertUninstalled(FAKE_DSA_1.caCertificate);
     }
@@ -68,14 +70,14 @@
      */
     public void testUninstallationIsSelective()
             throws CertificateException, GeneralSecurityException {
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_RSA_1.caCertificate));
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_DSA_1.caCertificate));
 
-        mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_DSA_1.caCertificate);
+        mDevicePolicyManager.uninstallCaCert(mAdmin, FAKE_DSA_1.caCertificate);
         assertInstalled(FAKE_RSA_1.caCertificate);
         assertUninstalled(FAKE_DSA_1.caCertificate);
 
-        mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
+        mDevicePolicyManager.uninstallCaCert(mAdmin, FAKE_RSA_1.caCertificate);
     }
 
     /**
@@ -84,10 +86,10 @@
      */
     public void testCanUninstallAllUserCaCerts()
             throws CertificateException, GeneralSecurityException {
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_RSA_1.caCertificate));
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_DSA_1.caCertificate));
 
-        mDevicePolicyManager.uninstallAllUserCaCerts(getWho());
+        mDevicePolicyManager.uninstallAllUserCaCerts(mAdmin);
         assertUninstalled(FAKE_RSA_1.caCertificate);
         assertUninstalled(FAKE_DSA_1.caCertificate);
     }
@@ -131,17 +133,15 @@
      */
     private boolean isCaCertInstalledAndTrusted(Certificate caCert)
             throws GeneralSecurityException, CertificateException {
-        boolean installed = mDevicePolicyManager.hasCaCertInstalled(getWho(), caCert.getEncoded());
+        boolean installed = mDevicePolicyManager.hasCaCertInstalled(mAdmin, caCert.getEncoded());
 
         boolean listed = false;
-        for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(getWho())) {
+        for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(mAdmin)) {
             if (caCert.equals(readCertificate(certBuffer))) {
                 listed = true;
             }
         }
 
-        NetworkSecurityPolicy.getInstance().handleTrustStorageUpdate();
-
         // Verify that the user added CA is reflected in the default X509TrustManager.
         final TrustManagerFactory tmf =
                 TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
@@ -153,7 +153,7 @@
         boolean userAddedCertificate = xtm.isUserAddedCertificate((X509Certificate) caCert);
 
         // All three responses should match - if an installed certificate isn't trusted or (worse)
-        // a trusted certificate isn't even installed we should 
+        // a trusted certificate isn't even installed we should fail now, loudly.
         assertEquals(installed, listed);
         assertEquals(installed, trusted);
         assertEquals(installed, userAddedCertificate);
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java
index 3072251..41bb626 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java
@@ -65,7 +65,6 @@
     private static final int ICMP_ECHO_REQUEST = 0x08;
     private static final int ICMP_ECHO_REPLY = 0x00;
     private static final int NETWORK_TIMEOUT_MS = 5000;
-    private static final int NETWORK_SETTLE_GRACE_MS = 100;
     private static final ComponentName ADMIN_RECEIVER_COMPONENT =
             BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT;
 
@@ -93,8 +92,6 @@
             if (!vpnLatch.await(NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
                 fail("Took too long waiting to establish a VPN-backed connection");
             }
-            // Give the VPN a moment to start transmitting data.
-            Thread.sleep(NETWORK_SETTLE_GRACE_MS);
         } catch (InterruptedException | PackageManager.NameNotFoundException e) {
             fail("Failed to send ping: " + e);
         } finally {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index 18d1b8b..197f5a7 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil compatibility-device-util
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index 64d4079..07d006c 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -25,8 +25,7 @@
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
 
-    <!-- Add a network security config that trusts user added CAs for tests -->
-    <application android:networkSecurityConfig="@xml/network_security_config"
+    <application
         android:testOnly="true">
 
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
index 219dfc2..cc4a8b0 100755
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
@@ -15,8 +15,8 @@
  */
 package com.android.cts.deviceowner;
 
+import static android.cts.util.FakeKeys.FAKE_RSA_1;
 import static com.android.cts.deviceowner.BaseDeviceOwnerTest.getWho;
-import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
 
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
index eb4a091..19fd3bd 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
-LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner android-support-test
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
index 85c74f9..7003012 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
 LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner compatibility-device-util \
-	ub-uiautomator
+	ub-uiautomator android-support-test
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 7b40ff1..c2a9bc1 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -110,6 +110,13 @@
         super.tearDown();
     }
 
+    public void testCaCertManagement() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        executeDeviceTestClass(".CaCertManagementTest");
+    }
+
     public void testResetPassword() throws Exception {
         if (!mHasFeature) {
             return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 4748b35..a877525 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -84,10 +84,6 @@
         super.tearDown();
     }
 
-    public void testCaCertManagement() throws Exception {
-        executeDeviceOwnerTest("CaCertManagementTest");
-    }
-
     public void testDeviceOwnerSetup() throws Exception {
         executeDeviceOwnerTest("DeviceOwnerSetupTest");
     }
diff --git a/hostsidetests/net/aidl/Android.mk b/hostsidetests/net/aidl/Android.mk
index a7ec6ef..4aa55b6 100644
--- a/hostsidetests/net/aidl/Android.mk
+++ b/hostsidetests/net/aidl/Android.mk
@@ -19,4 +19,4 @@
 LOCAL_SDK_VERSION := current
 LOCAL_SRC_FILES := com/android/cts/net/hostside/IRemoteSocketFactory.aidl
 LOCAL_MODULE := CtsHostsideNetworkTestsAidl
-include $(BUILD_JAVA_LIBRARY)
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/hostsidetests/numberblocking/app/Android.mk b/hostsidetests/numberblocking/app/Android.mk
index 492a2ec..5755f84 100644
--- a/hostsidetests/numberblocking/app/Android.mk
+++ b/hostsidetests/numberblocking/app/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
 # tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/services/activityandwindowmanager/Android.mk b/hostsidetests/services/activityandwindowmanager/Android.mk
new file mode 100644
index 0000000..178cb8a
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/Android.mk
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/hostsidetests/services/activitymanager/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
similarity index 96%
rename from hostsidetests/services/activitymanager/Android.mk
rename to hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
index 0cf1f2b..972e747 100644
--- a/hostsidetests/services/activitymanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
@@ -24,6 +24,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util
 
 LOCAL_CTS_TEST_PACKAGE := android.server
 
diff --git a/hostsidetests/services/activitymanager/AndroidTest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/AndroidTest.xml
similarity index 100%
rename from hostsidetests/services/activitymanager/AndroidTest.xml
rename to hostsidetests/services/activityandwindowmanager/activitymanager/AndroidTest.xml
diff --git a/hostsidetests/services/activitymanager/OldAndroidTest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/OldAndroidTest.xml
similarity index 100%
rename from hostsidetests/services/activitymanager/OldAndroidTest.xml
rename to hostsidetests/services/activityandwindowmanager/activitymanager/OldAndroidTest.xml
diff --git a/hostsidetests/services/activitymanager/app/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/app/Android.mk
similarity index 100%
rename from hostsidetests/services/activitymanager/app/Android.mk
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/Android.mk
diff --git a/hostsidetests/services/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
similarity index 99%
rename from hostsidetests/services/activitymanager/app/AndroidManifest.xml
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index 00c6352..0a690e3 100755
--- a/hostsidetests/services/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -17,7 +17,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-          package="android.server.app">
+          package="android.server.cts">
 
     <application>
         <activity android:name=".TestActivity"
diff --git a/hostsidetests/services/activitymanager/app/res/values/styles.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
similarity index 100%
rename from hostsidetests/services/activitymanager/app/res/values/styles.xml
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/AbstractLifecycleLogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
similarity index 97%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/AbstractLifecycleLogActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
index e3026c9..8086ce9 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/AbstractLifecycleLogActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 import android.content.res.Configuration;
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/AlwaysFocusablePipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AlwaysFocusablePipActivity.java
similarity index 97%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/AlwaysFocusablePipActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AlwaysFocusablePipActivity.java
index b5c736d..84b4b45 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/AlwaysFocusablePipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AlwaysFocusablePipActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AutoEnterPipActivity.java
similarity index 96%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AutoEnterPipActivity.java
index 97bc041..9d68603 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AutoEnterPipActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomLeftLayoutActivity.java
similarity index 95%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomLeftLayoutActivity.java
index 27a6fe2..8de1cda 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomLeftLayoutActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomRightLayoutActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomRightLayoutActivity.java
similarity index 95%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/BottomRightLayoutActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomRightLayoutActivity.java
index 7a91510..24fa2fc 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomRightLayoutActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomRightLayoutActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/DockedActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DockedActivity.java
similarity index 95%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/DockedActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DockedActivity.java
index 427fd29..007df5f 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/DockedActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DockedActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/FreeformActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/FreeformActivity.java
similarity index 97%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/FreeformActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/FreeformActivity.java
index a1cb54c..c5f7cae 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/FreeformActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/FreeformActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchIntoPinnedStackPipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchIntoPinnedStackPipActivity.java
similarity index 96%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/LaunchIntoPinnedStackPipActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchIntoPinnedStackPipActivity.java
index 45386bf..23298a0 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchIntoPinnedStackPipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchIntoPinnedStackPipActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchPipOnPipActivity.java
similarity index 96%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchPipOnPipActivity.java
index d7b4cc1..1b9b729 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchPipOnPipActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchToSideActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchToSideActivity.java
similarity index 97%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/LaunchToSideActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchToSideActivity.java
index 6cdcbde..9607d1b 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchToSideActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchToSideActivity.java
@@ -1,4 +1,4 @@
-package android.server.app;
+package android.server.cts;
 
 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/NoRelaunchActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NoRelaunchActivity.java
similarity index 96%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/NoRelaunchActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NoRelaunchActivity.java
index 0058c13..9cc3b9d 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/NoRelaunchActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NoRelaunchActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 public class NoRelaunchActivity extends AbstractLifecycleLogActivity {
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NonResizeableActivity.java
similarity index 96%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NonResizeableActivity.java
index 6312b47..b871a8d 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NonResizeableActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 public class NonResizeableActivity extends AbstractLifecycleLogActivity {
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
similarity index 95%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
index b750389..1747acd 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/ResizeableActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ResizeableActivity.java
similarity index 98%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/ResizeableActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ResizeableActivity.java
index 747bfc1..02360a4 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/ResizeableActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ResizeableActivity.java
@@ -13,7 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package android.server.app;
+package android.server.cts;
 
 import android.content.res.Configuration;
 import android.graphics.Point;
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SingleInstanceActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleInstanceActivity.java
similarity index 95%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/SingleInstanceActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleInstanceActivity.java
index b745adc..e0eaecf 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SingleInstanceActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleInstanceActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SingleTaskActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleTaskActivity.java
similarity index 95%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/SingleTaskActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleTaskActivity.java
index 0a99ea3..7ffde13 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SingleTaskActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleTaskActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SlowCreateActivity.java
similarity index 96%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SlowCreateActivity.java
index 481f5be..a757165 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SlowCreateActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
similarity index 96%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
index a8e51d5..7dfcea3 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 public class TestActivity extends AbstractLifecycleLogActivity {
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TopLeftLayoutActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopLeftLayoutActivity.java
similarity index 95%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/TopLeftLayoutActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopLeftLayoutActivity.java
index 3a0267b..2305582 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TopLeftLayoutActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopLeftLayoutActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TopRightLayoutActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopRightLayoutActivity.java
similarity index 95%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/TopRightLayoutActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopRightLayoutActivity.java
index eb3b1b0..701d3db 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TopRightLayoutActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopRightLayoutActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TrampolineActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TrampolineActivity.java
similarity index 97%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/TrampolineActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TrampolineActivity.java
index 4b80482..b3f9444 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TrampolineActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TrampolineActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.os.Bundle;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TranslucentActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentActivity.java
similarity index 95%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/TranslucentActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentActivity.java
index 800080e..96697aa 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TranslucentActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TurnScreenOnActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnActivity.java
similarity index 97%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/TurnScreenOnActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnActivity.java
index 838a1d6..79e31b3 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TurnScreenOnActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/VisibleBehindActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
similarity index 96%
rename from hostsidetests/services/activitymanager/app/src/android/server/app/VisibleBehindActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
index cc8f273..29feba9 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/VisibleBehindActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package android.server.app;
+package android.server.cts;
 
 import android.app.Activity;
 import android.util.Log;
diff --git a/hostsidetests/services/activitymanager/appDisplaySize/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/Android.mk
similarity index 100%
rename from hostsidetests/services/activitymanager/appDisplaySize/Android.mk
rename to hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/Android.mk
diff --git a/hostsidetests/services/activitymanager/appDisplaySize/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/services/activitymanager/appDisplaySize/AndroidManifest.xml
rename to hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/AndroidManifest.xml
diff --git a/hostsidetests/services/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java
similarity index 92%
rename from hostsidetests/services/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java
index b3f8c39..5da44c7 100644
--- a/hostsidetests/services/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java
@@ -31,7 +31,7 @@
         if (extras != null && extras.getBoolean("launch_another_activity")) {
             Intent startIntent = new Intent();
             startIntent.setComponent(
-                    new ComponentName("android.server.app", "android.server.app.TestActivity"));
+                    new ComponentName("android.server.cts", "android.server.cts.TestActivity"));
             startActivity(startIntent);
         }
     }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java
new file mode 100644
index 0000000..ec985eb
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java
@@ -0,0 +1,99 @@
+/*
+ * 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.server.cts;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ActivityAndWindowManagerOverrideConfigTests extends ActivityManagerTestBase {
+    private static final String TEST_ACTIVITY_NAME = "LogConfigurationActivity";
+
+    private static final String AM_MOVE_TASK = "am stack movetask ";
+    private static final String AM_RESIZE_TASK = "am task resize ";
+
+    private class ConfigurationChangeObserver {
+        private final Pattern mConfigurationChangedPattern =
+            Pattern.compile("(.+): Configuration changed: ");
+        private final LinkedList<String> mLogs = new LinkedList();
+
+        public ConfigurationChangeObserver() {
+        }
+
+        public boolean findConfigurationChange(String activityName, int widthDp, int heightDp) throws DeviceNotAvailableException, InterruptedException {
+            int tries = 0;
+            boolean observed = false;
+            final Pattern mSpecificConfigurationChangedPattern = 
+                Pattern.compile("(.+): Configuration changed: " + widthDp + "," + heightDp);
+            while (tries < 5 && !observed) {
+                final String logs = mDevice.executeAdbCommand(
+                        "logcat", "-v", "brief", "-d", activityName + ":I", "*:S");
+                Collections.addAll(mLogs, logs.split("\\n"));
+                CLog.logAndDisplay(LogLevel.INFO, "Looking at logcat");
+                while (!mLogs.isEmpty()) {
+                    final String line = mLogs.pop().trim();
+                    CLog.logAndDisplay(LogLevel.INFO, line);
+                    Matcher matcher = mConfigurationChangedPattern.matcher(line);
+                    Matcher specificMatcher = mSpecificConfigurationChangedPattern.matcher(line);
+                    if (specificMatcher.matches()) {
+                        observed = true;
+                    } else {
+                        assertFalse("Expected configuration change with (" + widthDp + "," + heightDp + ") but found " + line, matcher.matches());
+                    }
+                }
+                tries++;
+                Thread.sleep(500);
+            }
+            return observed;
+        }
+    }
+
+    private void launchTestActivityInFreeform(final String activityName) throws Exception {
+        mDevice.executeShellCommand(getAmStartCmd(activityName));
+        mAmWmState.computeState(mDevice, new String[] {activityName});
+
+        final int taskId = getActivityTaskId(activityName);
+        mDevice.executeShellCommand(AM_MOVE_TASK + taskId + " " + FREEFORM_WORKSPACE_STACK_ID + " true");
+    }
+
+private void resizeTask(final String activityName, int width, int height) throws Exception {
+        final int taskId = getActivityTaskId(activityName);
+        final String cmd = AM_RESIZE_TASK + taskId + " " + 0 + "," + 0 +
+            "," + width + "," + height;
+        mDevice.executeShellCommand(cmd);
+    }
+
+public void testReceiveOverrideConfigFromRelayout() throws Exception {
+        launchTestActivityInFreeform(TEST_ACTIVITY_NAME);
+
+        clearLogcat();
+        resizeTask(TEST_ACTIVITY_NAME, 100, 100);
+        ConfigurationChangeObserver c = new ConfigurationChangeObserver();
+        assertTrue("Expected to observe configuration change when resizing", c.findConfigurationChange(TEST_ACTIVITY_NAME, 100, 100));
+        
+        clearLogcat();
+        setDeviceRotation(2);
+        assertTrue("Expected to observe configuration change after rotation", c.findConfigurationChange(TEST_ACTIVITY_NAME, 100, 100));
+    }
+}
+
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
similarity index 100%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
similarity index 98%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
index 0083be4..2c5255e 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
@@ -29,7 +29,7 @@
 
     public void testDashD() throws Exception {
         final String[] waitForActivitiesVisible = new String[] {TEST_ACTIVITY_NAME};
-        AmStartLogcatVerifier verifier = new AmStartLogcatVerifier("android.server.app", TEST_ACTIVITY_NAME);
+        AmStartLogcatVerifier verifier = new AmStartLogcatVerifier("android.server.cts", TEST_ACTIVITY_NAME);
 
         // Run at least 2 rounds to verify that -D works with an existing process.
         // -D could fail in this case if the force stop of process is broken.
@@ -53,7 +53,7 @@
 
     private void testDashW(final String entryActivity, final String actualActivity)
             throws Exception {
-        AmStartLogcatVerifier verifier = new AmStartLogcatVerifier("android.server.app", actualActivity);
+        AmStartLogcatVerifier verifier = new AmStartLogcatVerifier("android.server.cts", actualActivity);
 
         // Test cold start
         startActivityAndVerifyResult(verifier, entryActivity, actualActivity, true);
@@ -205,7 +205,7 @@
                     activityName = matcher.group(2);
                     // Ignore activitiy displays from other packages, we don't
                     // want some random activity starts to ruin our test.
-                    if (!activityName.startsWith("android.server.app")) {
+                    if (!activityName.startsWith("android.server.cts")) {
                         continue;
                     }
                     if (!shouldStart) {
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
similarity index 100%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
similarity index 100%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
similarity index 100%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
similarity index 100%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
similarity index 100%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
similarity index 100%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
similarity index 100%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/DisplaySizeTest.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/DisplaySizeTest.java
similarity index 97%
rename from hostsidetests/services/activitymanager/src/android/server/cts/DisplaySizeTest.java
rename to hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/DisplaySizeTest.java
index 4dbb704..b093021 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/DisplaySizeTest.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/DisplaySizeTest.java
@@ -52,7 +52,7 @@
 
             // Ensure app process is stopped.
             forceStopPackage("android.displaysize.app");
-            forceStopPackage("android.server.app");
+            forceStopPackage("android.server.cts");
         } catch (DeviceNotAvailableException e) {
             // Do nothing.
         }
@@ -60,7 +60,7 @@
 
     public void testCompatibilityDialog() throws Exception {
         // Launch some other app (not to perform density change on launcher).
-        startActivity("android.server.app", "TestActivity");
+        startActivity("android.server.cts", "TestActivity");
         verifyWindowDisplayed("TestActivity", ACTIVITY_TIMEOUT_MILLIS);
 
         setUnsupportedDensity();
diff --git a/hostsidetests/services/activityandwindowmanager/util/Android.mk b/hostsidetests/services/activityandwindowmanager/util/Android.mk
new file mode 100644
index 0000000..ac91d35
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/util/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+
+LOCAL_MODULE := cts-amwm-util
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
similarity index 98%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
rename to hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
index bb7f521..0ee9522 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
@@ -35,7 +35,7 @@
 import static android.server.cts.StateLogger.log;
 
 /** Combined state of the activity manager and window manager. */
-class ActivityAndWindowManagersState extends Assert {
+public class ActivityAndWindowManagersState extends Assert {
 
     // Clone of android DisplayMetrics.DENSITY_DEFAULT (DENSITY_MEDIUM)
     // (Needed in host-side tests to convert dp to px.)
@@ -57,7 +57,7 @@
      * @param device test device.
      * @param waitForActivitiesVisible array of activity names to wait for.
      */
-    void computeState(ITestDevice device, String[] waitForActivitiesVisible) throws Exception {
+    public void computeState(ITestDevice device, String[] waitForActivitiesVisible) throws Exception {
         computeState(device, waitForActivitiesVisible, true);
     }
 
@@ -222,7 +222,7 @@
         return mAmState;
     }
 
-    WindowManagerState getWmState() {
+    public WindowManagerState getWmState() {
         return mWmState;
     }
 
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
similarity index 97%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
rename to hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
index d392e00..fea300c 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
@@ -45,18 +45,18 @@
 
     private final Pattern mDisplayIdPattern = Pattern.compile("Display #(\\d+)");
     private final Pattern mStackIdPattern = Pattern.compile("Stack #(\\d+)\\:");
-    private final Pattern mFocusedActivityPattern =
-            Pattern.compile("mFocusedActivity\\: ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)\\}");
+    private final Pattern mResumedActivityPattern =
+            Pattern.compile("ResumedActivity\\: ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)\\}");
     private final Pattern mFocusedStackPattern =
             Pattern.compile("mFocusedStack=ActivityStack\\{(.+) stackId=(\\d+), (.+)\\}(.+)");
 
     private final Pattern[] mExtractStackExitPatterns =
-            { mStackIdPattern, mFocusedActivityPattern, mFocusedStackPattern};
+            { mStackIdPattern, mResumedActivityPattern, mFocusedStackPattern};
 
     // Stacks in z-order with the top most at the front of the list.
     private final List<ActivityStack> mStacks = new ArrayList();
     private int mFocusedStackId = -1;
-    private String mFocusedActivityRecord = null;
+    private String mResumedActivityRecord = null;
     private final List<String> mResumedActivities = new ArrayList();
     private final LinkedList<String> mSysDump = new LinkedList();
 
@@ -88,7 +88,7 @@
             dump = outputReceiver.getOutput();
             parseSysDump(dump);
 
-            retry = mStacks.isEmpty() || mFocusedStackId == -1 || mFocusedActivityRecord == null
+            retry = mStacks.isEmpty() || mFocusedStackId == -1 || mResumedActivityRecord == null
                     || mResumedActivities.isEmpty();
         } while (retry && retriesLeft-- > 0);
 
@@ -102,7 +102,7 @@
         if (mFocusedStackId == -1) {
             logE("No focused stack found...");
         }
-        if (mFocusedActivityRecord == null) {
+        if (mResumedActivityRecord == null) {
             logE("No focused activity found...");
         }
         if (mResumedActivities.isEmpty()) {
@@ -139,11 +139,11 @@
                 continue;
             }
 
-            matcher = mFocusedActivityPattern.matcher(line);
+            matcher = mResumedActivityPattern.matcher(line);
             if (matcher.matches()) {
                 log(line);
-                mFocusedActivityRecord = matcher.group(3);
-                log(mFocusedActivityRecord);
+                mResumedActivityRecord = matcher.group(3);
+                log(mResumedActivityRecord);
                 continue;
             }
 
@@ -160,7 +160,7 @@
     private void reset() {
         mStacks.clear();
         mFocusedStackId = -1;
-        mFocusedActivityRecord = null;
+        mResumedActivityRecord = null;
         mResumedActivities.clear();
         mSysDump.clear();
     }
@@ -174,7 +174,7 @@
     }
 
     String getFocusedActivity() {
-        return mFocusedActivityRecord;
+        return mResumedActivityRecord;
     }
 
     String getResumedActivity() {
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
similarity index 96%
rename from hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java
rename to hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index 7ef163e..4dd3aa8 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -60,7 +60,7 @@
 
     private static final String AM_STACK_LIST = "am stack list";
 
-    private static final String AM_FORCE_STOP_TEST_PACKAGE = "am force-stop android.server.app";
+    private static final String AM_FORCE_STOP_TEST_PACKAGE = "am force-stop android.server.cts";
 
     private static final String AM_REMOVE_STACK = "am stack remove ";
 
@@ -76,6 +76,8 @@
 
     private static final String INPUT_KEYEVENT_HOME = "input keyevent 3";
 
+    static String componentName = "android.server.cts";
+
     /** A reference to the device under test. */
     protected ITestDevice mDevice;
 
@@ -85,16 +87,29 @@
         return "am start -n " + getActivityComponentName(activityName);
     }
 
+    protected static String getAmStartCmd(final String activityName,
+            final String extraDataName,
+            final String extraDataValue) {
+        String base = getAmStartCmd(activityName);
+        return base + " --es " + extraDataName + " " + extraDataValue;
+    }
+
     protected static String getAmStartCmdOverHome(final String activityName) {
         return "am start --activity-task-on-home -n " + getActivityComponentName(activityName);
     }
 
     static String getActivityComponentName(final String activityName) {
-        return "android.server.app/." + activityName;
+        return componentName + "/." + activityName;
+    }
+
+    // A little ugly, but lets avoid having to strip static everywhere for
+    // now.
+    public static void setComponentName(String name) {
+        componentName = name;
     }
 
     static String getWindowName(final String activityName) {
-        return "android.server.app/android.server.app." + activityName;
+        return componentName + "/" + componentName + "." + activityName;
     }
 
     protected ActivityAndWindowManagersState mAmWmState = new ActivityAndWindowManagersState();
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/StateLogger.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/StateLogger.java
similarity index 100%
rename from hostsidetests/services/activitymanager/src/android/server/cts/StateLogger.java
rename to hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/StateLogger.java
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
similarity index 89%
rename from hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
rename to hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
index a057013..82afb70 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
@@ -34,7 +34,7 @@
 import static android.server.cts.StateLogger.log;
 import static android.server.cts.StateLogger.logE;
 
-class WindowManagerState {
+public class WindowManagerState {
     private static final String DUMPSYS_WINDOWS_APPS = "dumpsys window apps";
     private static final String DUMPSYS_WINDOWS_VISIBLE_APPS = "dumpsys window visible-apps";
 
@@ -215,7 +215,7 @@
         }
     }
 
-    void getMatchingWindowState(final String windowName, List<WindowState> windowList) {
+    public void getMatchingWindowState(final String windowName, List<WindowState> windowList) {
         windowList.clear();
         for (WindowState ws : mWindowStates) {
             if (windowName.equals(ws.getName())) {
@@ -586,14 +586,23 @@
         }
     }
 
-    static class WindowState extends WindowContainer {
+    public static class WindowState extends WindowContainer {
         private static final String TAG = "[WindowState] ";
 
         private static final String RECT_STR = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]";
+        private static final Pattern sMainFramePattern = Pattern.compile("mFrame=" + RECT_STR + ".+");
         private static final Pattern sFramePattern =
                 Pattern.compile("Frames: containing=" + RECT_STR + " parent=" + RECT_STR);
+        private static final Pattern sContentFramePattern =
+            Pattern.compile("content=" + RECT_STR + " .+");
         private static final Pattern sWindowAssociationPattern =
                 Pattern.compile("mDisplayId=(\\d+) stackId=(\\d+) (.+)");
+        private static final Pattern sSurfaceInsetsPattern =
+            Pattern.compile("Cur insets.+surface=" + RECT_STR + ".+");
+        private static final Pattern sLayerPattern =
+            Pattern.compile("Surface:.+layer=(\\d+).+");
+        private static final Pattern sCropPattern =
+            Pattern.compile(".+mLastClipRect=" + RECT_STR + ".*");
 
         private final String mName;
         private final String mAppToken;
@@ -601,8 +610,13 @@
         private final boolean mExiting;
         private int mDisplayId;
         private int mStackId;
+        private int mLayer;
         private Rectangle mContainingFrame = new Rectangle();
         private Rectangle mParentFrame = new Rectangle();
+        private Rectangle mContentFrame = new Rectangle();
+        private Rectangle mFrame = new Rectangle();
+        private Rectangle mSurfaceInsets = new Rectangle();
+        private Rectangle mCrop = new Rectangle();
 
         private WindowState(Matcher matcher, boolean starting, boolean exiting) {
             mName = matcher.group(4);
@@ -611,7 +625,7 @@
             mExiting = exiting;
         }
 
-        String getName() {
+        public String getName() {
             return mName;
         }
 
@@ -635,14 +649,34 @@
             return mStackId;
         }
 
+        int getLayer() {
+            return mLayer;
+        }
+
         Rectangle getContainingFrame() {
             return mContainingFrame;
         }
 
+        Rectangle getFrame() {
+            return mFrame;
+        }
+
+        Rectangle getSurfaceInsets() {
+            return mSurfaceInsets;
+        }
+
+        Rectangle getContentFrame() {
+            return mContentFrame;
+        }
+
         Rectangle getParentFrame() {
             return mParentFrame;
         }
 
+        Rectangle getCrop() {
+            return mCrop;
+        }
+
         static WindowState create(LinkedList<String> dump, Pattern[] exitPatterns) {
             final String line = dump.peek().trim();
 
@@ -685,6 +719,13 @@
                     continue;
                 }
 
+                matcher = sMainFramePattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "MAIN WINDOW FRAME: " + line);
+                    mFrame = extractBounds(matcher);
+                    continue;
+                }
+
                 matcher = sFramePattern.matcher(line);
                 if (matcher.matches()) {
                     log(TAG + "FRAME: " + line);
@@ -692,6 +733,29 @@
                     continue;
                 }
 
+                matcher = sContentFramePattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "CONTENT FRAME: " + line);
+                    mContentFrame = extractBounds(matcher);
+                }
+
+                matcher = sSurfaceInsetsPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "INSETS: " + line);
+                    mSurfaceInsets = extractBounds(matcher);
+                }
+
+                matcher = sLayerPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "LAYER: " + line);
+                    mLayer = Integer.valueOf(matcher.group(1));
+                }
+
+                matcher = sCropPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "CROP: " + line);
+                    mCrop = extractBounds(matcher);
+                }
                 // Extract other info here if needed
             }
         }
diff --git a/hostsidetests/services/windowmanager/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
similarity index 83%
rename from hostsidetests/services/windowmanager/Android.mk
rename to hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
index eeac27b..0dda353 100644
--- a/hostsidetests/services/windowmanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
@@ -19,13 +19,14 @@
 LOCAL_MODULE_TAGS := tests
 
 # Must match the package name in OldCtsTestCaseList.mk
-LOCAL_MODULE := CtsDragAndDropHostTestCases
+LOCAL_MODULE := CtsWindowManagerHostTestCases
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt CtsServicesHostTestCases
+LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util
 
-LOCAL_CTS_TEST_PACKAGE := android.wm.cts
+LOCAL_CTS_TEST_PACKAGE := android.server.cts
 
 LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
 
diff --git a/hostsidetests/services/windowmanager/AndroidTest.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/AndroidTest.xml
similarity index 88%
rename from hostsidetests/services/windowmanager/AndroidTest.xml
rename to hostsidetests/services/activityandwindowmanager/windowmanager/AndroidTest.xml
index 8346b72..a66f8f1 100644
--- a/hostsidetests/services/windowmanager/AndroidTest.xml
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/AndroidTest.xml
@@ -19,8 +19,9 @@
         <option name="test-file-name" value="CtsDragAndDropSourceApp.apk" />
         <option name="test-file-name" value="CtsDragAndDropTargetApp.apk" />
         <option name="test-file-name" value="CtsDragAndDropTargetAppSdk23.apk" />
+        <option name="test-file-name" value="CtsDeviceWindowFramesTestApp.apk" />
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
-        <option name="jar" value="CtsDragAndDropHostTestCases.jar" />
+        <option name="jar" value="CtsWindowManagerHostTestCases.jar" />
     </test>
 </configuration>
diff --git a/hostsidetests/services/windowmanager/OldAndroidTest.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/OldAndroidTest.xml
similarity index 100%
rename from hostsidetests/services/windowmanager/OldAndroidTest.xml
rename to hostsidetests/services/activityandwindowmanager/windowmanager/OldAndroidTest.xml
diff --git a/hostsidetests/services/windowmanager/dndsourceapp/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/Android.mk
similarity index 100%
rename from hostsidetests/services/windowmanager/dndsourceapp/Android.mk
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/Android.mk
diff --git a/hostsidetests/services/windowmanager/dndsourceapp/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/services/windowmanager/dndsourceapp/AndroidManifest.xml
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/AndroidManifest.xml
diff --git a/hostsidetests/services/windowmanager/dndsourceapp/res/layout/source_activity.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/res/layout/source_activity.xml
similarity index 100%
rename from hostsidetests/services/windowmanager/dndsourceapp/res/layout/source_activity.xml
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/res/layout/source_activity.xml
diff --git a/hostsidetests/services/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java
similarity index 100%
rename from hostsidetests/services/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java
diff --git a/hostsidetests/services/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSourceContentProvider.java b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSourceContentProvider.java
similarity index 100%
rename from hostsidetests/services/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSourceContentProvider.java
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSourceContentProvider.java
diff --git a/hostsidetests/services/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSourceCursor.java b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSourceCursor.java
similarity index 100%
rename from hostsidetests/services/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSourceCursor.java
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSourceCursor.java
diff --git a/hostsidetests/services/windowmanager/dndtargetapp/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/Android.mk
similarity index 100%
rename from hostsidetests/services/windowmanager/dndtargetapp/Android.mk
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/Android.mk
diff --git a/hostsidetests/services/windowmanager/dndtargetapp/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/services/windowmanager/dndtargetapp/AndroidManifest.xml
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/AndroidManifest.xml
diff --git a/hostsidetests/services/windowmanager/dndtargetapp/res/layout/target_activity.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/res/layout/target_activity.xml
similarity index 100%
rename from hostsidetests/services/windowmanager/dndtargetapp/res/layout/target_activity.xml
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/res/layout/target_activity.xml
diff --git a/hostsidetests/services/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java
similarity index 72%
rename from hostsidetests/services/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java
index 904a422..8892c6f 100644
--- a/hostsidetests/services/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.content.ClipData;
+import android.content.ClipDescription;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
@@ -33,12 +34,20 @@
     public static final String LOG_TAG = "DropTarget";
 
     private static final String RESULT_KEY_DRAG_STARTED = "DRAG_STARTED";
+    private static final String RESULT_KEY_DRAG_ENDED = "DRAG_ENDED";
     private static final String RESULT_KEY_EXTRAS = "EXTRAS";
     private static final String RESULT_KEY_DROP_RESULT = "DROP";
     private static final String RESULT_KEY_DETAILS = "DETAILS";
+    private static final String RESULT_KEY_ACCESS_AFTER = "AFTER";
+    private static final String RESULT_KEY_ACCESS_BEFORE = "BEFORE";
+    private static final String RESULT_KEY_CLIP_DATA_ERROR = "CLIP_DATA_ERROR";
+    private static final String RESULT_KEY_CLIP_DESCR_ERROR = "CLIP_DESCR_ERROR";
+    private static final String RESULT_KEY_LOCAL_STATE_ERROR = "LOCAL_STATE_ERROR";
 
     public static final String RESULT_OK = "OK";
     public static final String RESULT_EXCEPTION = "Exception";
+    public static final String RESULT_MISSING = "MISSING";
+    public static final String RESULT_LEAKING = "LEAKING";
 
     protected static final String MAGIC_VALUE = "42";
 
@@ -94,6 +103,8 @@
 
         @Override
         public boolean onDrag(View v, DragEvent event) {
+            checkDragEvent(event);
+
             switch (event.getAction()) {
                 case DragEvent.ACTION_DRAG_STARTED:
                     logResult(RESULT_KEY_DRAG_STARTED, RESULT_OK);
@@ -110,17 +121,18 @@
                     return true;
 
                 case DragEvent.ACTION_DROP:
-                    String result;
-                    try {
-                        result = processDrop(event, requestPermissions);
-                    } catch (Exception e) {
-                        result = RESULT_EXCEPTION;
-                        logResult(RESULT_KEY_DETAILS, e.getMessage());
-                    }
-                    logResult(RESULT_KEY_DROP_RESULT, result);
+                    // Try accessing the Uri without the permissions grant.
+                    accessContent(event, RESULT_KEY_ACCESS_BEFORE, false);
+
+                    // Try accessing the Uri with the permission grant (if required);
+                    accessContent(event, RESULT_KEY_DROP_RESULT, requestPermissions);
+
+                    // Try accessing the Uri after the permissions have been released.
+                    accessContent(event, RESULT_KEY_ACCESS_AFTER, false);
                     return true;
 
                 case DragEvent.ACTION_DRAG_ENDED:
+                    logResult(RESULT_KEY_DRAG_ENDED, RESULT_OK);
                     return true;
 
                 default:
@@ -128,6 +140,19 @@
             }
         }
 
+        private void accessContent(DragEvent event, String resultKey, boolean requestPermissions) {
+            String result;
+            try {
+                result = processDrop(event, requestPermissions);
+            } catch (SecurityException e) {
+                result = RESULT_EXCEPTION;
+                if (resultKey.equals(RESULT_KEY_DROP_RESULT)) {
+                    logResult(RESULT_KEY_DETAILS, e.getMessage());
+                }
+            }
+            logResult(resultKey, result);
+        }
+
         private String processDrop(DragEvent event, boolean requestPermissions) {
             final ClipData clipData = event.getClipData();
             if (clipData == null) {
@@ -165,6 +190,40 @@
         abstract protected String processUri(Uri uri);
     }
 
+    private void checkDragEvent(DragEvent event) {
+        final int action = event.getAction();
+
+        // ClipData should be available for ACTION_DROP only.
+        final ClipData clipData = event.getClipData();
+        if (action == DragEvent.ACTION_DROP) {
+            if (clipData == null) {
+                logResult(RESULT_KEY_CLIP_DATA_ERROR, RESULT_MISSING);
+            }
+        } else {
+            if (clipData != null) {
+                logResult(RESULT_KEY_CLIP_DATA_ERROR, RESULT_LEAKING + action);
+            }
+        }
+
+        // ClipDescription should be always available except for ACTION_DRAG_ENDED.
+        final ClipDescription clipDescription = event.getClipDescription();
+        if (action != DragEvent.ACTION_DRAG_ENDED) {
+            if (clipDescription == null) {
+                logResult(RESULT_KEY_CLIP_DESCR_ERROR, RESULT_MISSING + action);
+            }
+        } else {
+            if (clipDescription != null) {
+                logResult(RESULT_KEY_CLIP_DESCR_ERROR, RESULT_LEAKING);
+            }
+        }
+
+        // Local state should be always null for cross-app drags.
+        final Object localState = event.getLocalState();
+        if (localState != null) {
+            logResult(RESULT_KEY_LOCAL_STATE_ERROR, RESULT_LEAKING + action);
+        }
+    }
+
     private class OnDragUriReadListener extends OnDragUriListener {
         OnDragUriReadListener(boolean requestPermissions) {
             super(requestPermissions);
diff --git a/hostsidetests/services/windowmanager/dndtargetappsdk23/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/Android.mk
similarity index 100%
rename from hostsidetests/services/windowmanager/dndtargetappsdk23/Android.mk
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/Android.mk
diff --git a/hostsidetests/services/windowmanager/dndtargetappsdk23/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/services/windowmanager/dndtargetappsdk23/AndroidManifest.xml
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/AndroidManifest.xml
diff --git a/hostsidetests/services/windowmanager/dndtargetappsdk23/res/layout/target_activity.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/res/layout/target_activity.xml
similarity index 100%
rename from hostsidetests/services/windowmanager/dndtargetappsdk23/res/layout/target_activity.xml
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/res/layout/target_activity.xml
diff --git a/hostsidetests/services/windowmanager/dndtargetappsdk23/src/android/wm/cts/dndtargetappsdk23/DropTarget.java b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/src/android/wm/cts/dndtargetappsdk23/DropTarget.java
similarity index 100%
rename from hostsidetests/services/windowmanager/dndtargetappsdk23/src/android/wm/cts/dndtargetappsdk23/DropTarget.java
rename to hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetappsdk23/src/android/wm/cts/dndtargetappsdk23/DropTarget.java
diff --git a/hostsidetests/services/windowmanager/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/Android.mk
similarity index 64%
copy from hostsidetests/services/windowmanager/Android.mk
copy to hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/Android.mk
index eeac27b..e5aa610 100644
--- a/hostsidetests/services/windowmanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/Android.mk
@@ -12,27 +12,20 @@
 # 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)
 
+# Don't include this package in any target.
 LOCAL_MODULE_TAGS := tests
 
-# Must match the package name in OldCtsTestCaseList.mk
-LOCAL_MODULE := CtsDragAndDropHostTestCases
-
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_CTS_TEST_PACKAGE := android.wm.cts
-
-LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+LOCAL_SDK_VERSION := test_current
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+LOCAL_PACKAGE_NAME := CtsDeviceWindowFramesTestApp
 
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/AndroidManifest.xml
new file mode 100755
index 0000000..3d230c5
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+          package="android.server.FrameTestApp">
+    <application>
+        <activity android:name=".DialogTestActivity"
+                android:exported="true"
+        />
+        <activity android:name=".SurfaceViewTestActivity"
+                  android:exported="true"
+        />
+    </application>
+</manifest>
+
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/DialogTestActivity.java b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/DialogTestActivity.java
new file mode 100644
index 0000000..593cf34
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/DialogTestActivity.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.FrameTestApp;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.view.Window;
+import android.view.Gravity;
+
+public class DialogTestActivity extends Activity {
+
+    AlertDialog mDialog;
+
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+    }
+
+    protected void onStop() {
+        super.onStop();
+        mDialog.dismiss();
+    }
+    protected void onResume() {
+        super.onResume();
+        setupTest(getIntent());
+    }
+
+    private void setupTest(Intent intent) {
+        String testCase = intent.getStringExtra(
+                "android.server.FrameTestApp.DialogTestCase");
+        switch (testCase) {
+           case "MatchParent": {
+               testMatchParent();
+               break;
+           } case "MatchParentLayoutInOverscan": {
+               testMatchParentLayoutInOverscan();
+           }  break;
+           case "ExplicitSize": {
+               testExplicitSize();
+               break;
+           }
+           case "ExplicitSizeTopLeftGravity": {
+               testExplicitSizeTopLeftGravity();
+               break;
+           }
+           case "ExplicitSizeBottomRightGravity": {
+               testExplicitSizeBottomRightGravity();
+               break;
+           }
+           case "OversizedDimensions": {
+               testOversizedDimensions();
+               break;
+           }
+           case "OversizedDimensionsNoLimits": {
+               testOversizedDimensionsNoLimits();
+               break;
+           }
+           case "ExplicitPositionMatchParent": {
+               testExplicitPositionMatchParent();
+               break;
+           }
+           case "ExplicitPositionMatchParentNoLimits": {
+               testExplicitPositionMatchParentNoLimits();
+               break;
+           }
+           case "NoFocus": {
+               testNoFocus();
+               break;
+           }
+           case "WithMargins": {
+               testWithMargins();
+               break;
+           }
+           default:
+               break;
+        }
+    }
+
+    interface DialogLayoutParamsTest {
+        void doSetup(WindowManager.LayoutParams p);
+    }
+
+    private void doLayoutParamTest(DialogLayoutParamsTest t) {
+        mDialog = new AlertDialog.Builder(this).create();
+
+        mDialog.setMessage("Testing is fun!");
+        mDialog.setTitle("android.server.FrameTestApp/android.server.FrameTestApp.TestDialog");
+        mDialog.create();
+
+        Window w = mDialog.getWindow();
+        final WindowManager.LayoutParams params = w.getAttributes();
+        t.doSetup(params);
+        w.setAttributes(params);
+
+        mDialog.show();
+    }
+
+    private void testMatchParent() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.width = WindowManager.LayoutParams.MATCH_PARENT;
+            params.height = WindowManager.LayoutParams.MATCH_PARENT;
+        });
+    }
+
+    private void testMatchParentLayoutInOverscan() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.width = WindowManager.LayoutParams.MATCH_PARENT;
+            params.height = WindowManager.LayoutParams.MATCH_PARENT;
+            params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+            params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
+        });
+    }
+
+    private void testExplicitSize() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.width = 200;
+            params.height = 200;
+        });
+    }
+
+    private void testExplicitSizeTopLeftGravity() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.width = 200;
+            params.height = 200;
+            params.gravity = Gravity.TOP | Gravity.LEFT;
+        });
+    }
+
+    private void testExplicitSizeBottomRightGravity() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.width = 200;
+            params.height = 200;
+            params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+        });
+    }
+
+    private void testOversizedDimensions() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.width = 100000;
+            params.height = 100000;
+        });
+    }
+
+    private void testOversizedDimensionsNoLimits() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.width = 5000;
+            params.height = 5000;
+            params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+            params.gravity = Gravity.LEFT | Gravity.TOP;
+        });
+    }
+
+    private void testExplicitPositionMatchParent() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.width = WindowManager.LayoutParams.MATCH_PARENT;
+            params.height = WindowManager.LayoutParams.MATCH_PARENT;
+            params.x = 100;
+            params.y = 100;
+        });
+    }
+
+    private void testExplicitPositionMatchParentNoLimits() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.width = WindowManager.LayoutParams.MATCH_PARENT;
+            params.height = WindowManager.LayoutParams.MATCH_PARENT;
+            params.gravity = Gravity.LEFT | Gravity.TOP;
+            params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+            params.x = 100;
+            params.y = 100;
+        });
+    }
+
+    private void testNoFocus() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        });
+    }
+
+    private void testWithMargins() {
+        doLayoutParamTest((WindowManager.LayoutParams params) -> {
+            params.gravity = Gravity.LEFT | Gravity.TOP;
+            params.horizontalMargin = .25f;
+            params.verticalMargin = .35f;
+            params.width = 200;
+            params.height = 200;
+            params.x = 0;
+            params.y = 0;
+        });
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/SurfaceViewTestActivity.java b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/SurfaceViewTestActivity.java
new file mode 100644
index 0000000..0092619
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/SurfaceViewTestActivity.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.FrameTestApp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.view.Window;
+import android.view.Gravity;
+import android.view.SurfaceView;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+
+public class SurfaceViewTestActivity extends Activity {
+
+    SurfaceView mSurfaceView;
+
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+    }
+
+    protected void onResume() {
+        super.onResume();
+        setupTest(getIntent());
+    }
+
+    private void setupTest(Intent intent) {
+        String testCase = intent.getStringExtra(
+                "android.server.FrameTestApp.SurfaceViewTestCase");
+        switch (testCase) {
+            case "OnBottom": {
+                doOnBottomTest();
+                break;
+            }
+            case "OnTop": {
+                doOnTopTest();
+                break;
+            }
+            case "Oversized": {
+                doOversizedTest();
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    void doOnBottomTest() {
+        mSurfaceView = new SurfaceView(this);
+        setContentView(mSurfaceView);
+    }
+
+    void doOnTopTest() {
+        mSurfaceView = new SurfaceView(this);
+        mSurfaceView.setZOrderOnTop(true);
+        setContentView(mSurfaceView);
+    }
+
+    void doOversizedTest() {
+        mSurfaceView = new SurfaceView(this);
+        LayoutParams p = new LayoutParams(8000, 8000);
+        setContentView(mSurfaceView, p);
+    }
+}
diff --git a/hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
similarity index 90%
rename from hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java
rename to hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
index 8fc3264..904600e 100644
--- a/hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.wm.cts;
+package android.server.cts;
 
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -75,8 +75,14 @@
     private static final String TARGET_LOG_TAG = "DropTarget";
 
     private static final String RESULT_KEY_DRAG_STARTED = "DRAG_STARTED";
+    private static final String RESULT_KEY_DRAG_ENDED = "DRAG_ENDED";
     private static final String RESULT_KEY_EXTRAS = "EXTRAS";
     private static final String RESULT_KEY_DROP_RESULT = "DROP";
+    private static final String RESULT_KEY_ACCESS_BEFORE = "BEFORE";
+    private static final String RESULT_KEY_ACCESS_AFTER = "AFTER";
+    private static final String RESULT_KEY_CLIP_DATA_ERROR = "CLIP_DATA_ERROR";
+    private static final String RESULT_KEY_CLIP_DESCR_ERROR = "CLIP_DESCR_ERROR";
+    private static final String RESULT_KEY_LOCAL_STATE_ERROR = "LOCAL_STATE_ERROR";
 
     private static final String RESULT_OK = "OK";
     private static final String RESULT_EXCEPTION = "Exception";
@@ -265,7 +271,7 @@
     }
 
     private Map<String, String> getLogResults(String className) throws Exception {
-        int retryCount = 3;
+        int retryCount = 10;
         Map<String, String> output = new HashMap<String, String>();
         do {
 
@@ -279,7 +285,7 @@
                     }
                 }
             }
-            if (output.containsKey(RESULT_KEY_DROP_RESULT)) {
+            if (output.containsKey(RESULT_KEY_DRAG_ENDED)) {
                 return output;
             }
         } while (retryCount-- > 0);
@@ -301,8 +307,22 @@
 
         mResults = getLogResults(TARGET_LOG_TAG);
         assertResult(RESULT_KEY_DROP_RESULT, expectedDropResult);
+        if (expectedDropResult != null) {
+            assertResult(RESULT_KEY_ACCESS_BEFORE, RESULT_EXCEPTION);
+            assertResult(RESULT_KEY_ACCESS_AFTER, RESULT_EXCEPTION);
+            assertListenerResults(RESULT_OK);
+        }
     }
 
+    private void assertListenerResults(String expectedResult) {
+        assertResult(RESULT_KEY_DRAG_STARTED, expectedResult);
+        assertResult(RESULT_KEY_DRAG_ENDED, expectedResult);
+        assertResult(RESULT_KEY_EXTRAS, expectedResult);
+
+        assertResult(RESULT_KEY_CLIP_DATA_ERROR, null);
+        assertResult(RESULT_KEY_CLIP_DESCR_ERROR, null);
+        assertResult(RESULT_KEY_LOCAL_STATE_ERROR, null);
+    }
 
     private void assertResult(String resultKey, String expectedResult) {
         if (expectedResult == null) {
@@ -311,31 +331,28 @@
             }
         } else {
             assertTrue("Missing " + resultKey, mResults.containsKey(resultKey));
-            assertEquals(expectedResult, mResults.get(resultKey));
+            assertEquals(resultKey + " result mismatch,", expectedResult, mResults.get(resultKey));
         }
     }
 
     public void testCancelSoon() throws Exception {
         doTestDragAndDrop(CANCEL_SOON, REQUEST_NONE, null);
-        assertResult(RESULT_KEY_DRAG_STARTED, RESULT_OK);
-        assertResult(RESULT_KEY_EXTRAS, RESULT_OK);
+        assertListenerResults(RESULT_OK);
     }
 
     public void testDisallowGlobal() throws Exception {
         doTestDragAndDrop(DISALLOW_GLOBAL, REQUEST_NONE, null);
-        assertResult(RESULT_KEY_DRAG_STARTED, null);
+        assertListenerResults(null);
     }
 
     public void testDisallowGlobalBelowSdk24() throws Exception {
         mTargetPackageName = TARGET_23_PACKAGE_NAME;
         doTestDragAndDrop(GRANT_NONE, REQUEST_NONE, null);
-        assertResult(RESULT_KEY_DRAG_STARTED, null);
+        assertListenerResults(null);
     }
 
     public void testGrantNoneRequestNone() throws Exception {
         doTestDragAndDrop(GRANT_NONE, REQUEST_NONE, RESULT_EXCEPTION);
-        assertResult(RESULT_KEY_DRAG_STARTED, RESULT_OK);
-        assertResult(RESULT_KEY_EXTRAS, RESULT_OK);
     }
 
     public void testGrantNoneRequestRead() throws Exception {
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/DialogFrameTests.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/DialogFrameTests.java
new file mode 100644
index 0000000..ad8fac3
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/DialogFrameTests.java
@@ -0,0 +1,255 @@
+/*
+ * 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.server.cts;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.awt.Rectangle;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import android.server.cts.ActivityManagerTestBase;
+import android.server.cts.WindowManagerState.WindowState;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DialogFrameTests extends ActivityManagerTestBase {
+    static final String ACTIVITY_NAME = "DialogTestActivity";
+    static final String INTENT_KEY = "android.server.FrameTestApp.DialogTestCase";
+    static final String baseWindowName =
+        "android.server.FrameTestApp/android.server.FrameTestApp.";
+
+    private List<WindowState> mWindowList = new ArrayList();
+
+    public void startTestCase(String testCase) throws Exception{
+        setComponentName("android.server.FrameTestApp");
+        String cmd = getAmStartCmd(ACTIVITY_NAME, INTENT_KEY, testCase);
+        CLog.logAndDisplay(LogLevel.INFO, cmd);
+        executeShellCommand(cmd);
+    }
+
+    public void startTestCaseDocked(String testCase) throws Exception{
+        setComponentName("android.server.FrameTestApp");
+        String cmd = getAmStartCmd(ACTIVITY_NAME, INTENT_KEY, testCase);
+        CLog.logAndDisplay(LogLevel.INFO, cmd);
+        executeShellCommand(cmd);
+        moveActivityToDockStack("DialogTestActivity");
+    }
+
+    void stopTestCase() throws Exception{
+        executeShellCommand("am force-stop android.server.FrameTestApp");
+    }
+
+    WindowState getSingleWindow(String windowName) {
+        try {
+            mAmWmState.getWmState().getMatchingWindowState(baseWindowName + windowName, mWindowList);
+            return mWindowList.get(0);
+        } catch (Exception e) {
+            CLog.logAndDisplay(LogLevel.INFO, "Couldn't find window: " + windowName);
+            return null;
+        }
+    }
+
+    interface DialogWindowTest {
+        void doTest(WindowState parent, WindowState dialog);
+    }
+
+    void doSingleTest(DialogWindowTest t) throws Exception {
+        final String[] waitForVisible = new String[] { "TestDialog" };
+
+        mAmWmState.computeState(mDevice, waitForVisible);
+        WindowState dialog = getSingleWindow("TestDialog");
+        WindowState parent = getSingleWindow("DialogTestActivity");
+
+        t.doTest(parent, dialog);
+        stopTestCase();
+    }
+
+    void doFullscreenTest(String testCase, DialogWindowTest t) throws Exception {
+        CLog.logAndDisplay(LogLevel.INFO, "Running test fullscreen");
+        startTestCase(testCase);
+        doSingleTest(t);
+    }
+
+    void doDockedTest(String testCase, DialogWindowTest t) throws Exception {
+        CLog.logAndDisplay(LogLevel.INFO, "Running test docked");
+        startTestCaseDocked(testCase);
+        doSingleTest(t);
+    }
+
+    void doDialogTest(String testCase, DialogWindowTest t) throws Exception {
+        doFullscreenTest(testCase, t);
+        doDockedTest(testCase, t);
+    }
+
+    // With Width and Height as MATCH_PARENT we should fill
+    // the same content frame as the main activity window
+    public void testMatchParentDialog() throws Exception {
+        doDialogTest("MatchParent",
+            (WindowState parent, WindowState dialog) -> {
+                assertEquals(parent.getContentFrame(), dialog.getFrame());
+            });
+    }
+
+    // If we have LAYOUT_IN_SCREEN and LAYOUT_IN_OVERSCAN with MATCH_PARENT,
+    // we will not be constrained to the insets and so we will be the same size
+    // as the main window main frame.
+    public void testMatchParentDialogLayoutInOverscan() throws Exception {
+        doDialogTest("MatchParentLayoutInOverscan",
+            (WindowState parent, WindowState dialog) -> {
+                assertEquals(parent.getFrame(), dialog.getFrame());
+            });
+    }
+
+    static final int explicitDimension = 200;
+
+    // The default gravity for dialogs should center them.
+    public void testExplicitSizeDefaultGravity() throws Exception {
+        doDialogTest("ExplicitSize",
+            (WindowState parent, WindowState dialog) -> {
+                Rectangle contentFrame = parent.getContentFrame();
+                Rectangle expectedFrame = new Rectangle(
+                        contentFrame.x + (contentFrame.width - explicitDimension)/2,
+                        contentFrame.y + (contentFrame.height - explicitDimension)/2,
+                        explicitDimension, explicitDimension);
+                assertEquals(expectedFrame, dialog.getFrame());
+            });
+    }
+
+    public void testExplicitSizeTopLeftGravity() throws Exception {
+        doDialogTest("ExplicitSizeTopLeftGravity",
+            (WindowState parent, WindowState dialog) -> {
+                Rectangle contentFrame = parent.getContentFrame();
+                Rectangle expectedFrame = new Rectangle(
+                        contentFrame.x,
+                        contentFrame.y,
+                        explicitDimension,
+                        explicitDimension);
+                assertEquals(expectedFrame, dialog.getFrame());
+            });
+    }
+
+    public void testExplicitSizeBottomRightGravity() throws Exception {
+        doDialogTest("ExplicitSizeBottomRightGravity",
+            (WindowState parent, WindowState dialog) -> {
+                Rectangle contentFrame = parent.getContentFrame();
+                Rectangle expectedFrame = new Rectangle(
+                        contentFrame.x + contentFrame.width - explicitDimension,
+                        contentFrame.y + contentFrame.height - explicitDimension,
+                        explicitDimension, explicitDimension);
+                assertEquals(expectedFrame, dialog.getFrame());
+            });
+    }
+
+    // TODO: Commented out for now because it doesn't work. We end up
+    // insetting the decor on the bottom. I think this is a bug
+    // probably in the default dialog flags:
+    // b/30127373
+    //    public void testOversizedDimensions() throws Exception {
+    //        doDialogTest("OversizedDimensions",
+    //            (WindowState parent, WindowState dialog) -> {
+    // With the default flags oversize should result in clipping to
+    // parent frame.
+    //                assertEquals(parent.getContentFrame(), dialog.getFrame());
+    //         });
+    //    }
+
+    static final int oversizedDimension = 5000;
+    // With FLAG_LAYOUT_NO_LIMITS  we should get the size we request, even if its much
+    // larger than the screen.
+    public void testOversizedDimensionsNoLimits() throws Exception {
+        doDialogTest("OversizedDimensionsNoLimits",
+            (WindowState parent, WindowState dialog) -> {
+                Rectangle contentFrame = parent.getContentFrame();
+                Rectangle expectedFrame = new Rectangle(contentFrame.x, contentFrame.y,
+                        oversizedDimension, oversizedDimension);
+                assertEquals(expectedFrame, dialog.getFrame());
+            });
+    }
+
+    // If we request the MATCH_PARENT and a non-zero position, we wouldn't be
+    // able to fit all of our content, so we should be adjusted to just fit the
+    // content frame.
+    public void testExplicitPositionMatchParent() throws Exception {
+        doDialogTest("ExplicitPositionMatchParent",
+             (WindowState parent, WindowState dialog) -> {
+                    assertEquals(parent.getContentFrame(),
+                            dialog.getFrame());
+             });
+    }
+
+    // Unless we pass NO_LIMITS in which case our requested position should
+    // be honored.
+    public void testExplicitPositionMatchParentNoLimits() throws Exception {
+        final int explicitPosition = 100;
+        doDialogTest("ExplicitPositionMatchParentNoLimits",
+            (WindowState parent, WindowState dialog) -> {
+                Rectangle contentFrame = parent.getContentFrame();
+                Rectangle expectedFrame = new Rectangle(contentFrame.x + explicitPosition,
+                        contentFrame.y + explicitPosition,
+                        contentFrame.width,
+                        contentFrame.height);
+            });
+    }
+
+    // We run the two focus tests fullscreen only because switching to the
+    // docked stack will strip away focus from the task anyway.
+    public void testDialogReceivesFocus() throws Exception {
+        doFullscreenTest("MatchParent",
+            (WindowState parent, WindowState dialog) -> {
+                assertEquals(dialog.getName(), mAmWmState.getWmState().getFocusedWindow());
+        });
+    }
+
+    public void testNoFocusDialog() throws Exception {
+        doFullscreenTest("NoFocus",
+            (WindowState parent, WindowState dialog) -> {
+                assertEquals(parent.getName(), mAmWmState.getWmState().getFocusedWindow());
+        });
+    }
+
+    public void testMarginsArePercentagesOfContentFrame() throws Exception {
+        float horizontalMargin = .25f;
+        float verticalMargin = .35f;
+        doDialogTest("WithMargins",
+            (WindowState parent, WindowState dialog) -> {
+                Rectangle frame = parent.getContentFrame();
+                Rectangle expectedFrame = new Rectangle(
+                        (int)(horizontalMargin*frame.width + frame.x),
+                        (int)(verticalMargin*frame.height + frame.y),
+                        explicitDimension,
+                        explicitDimension);
+                assertEquals(expectedFrame, dialog.getFrame());
+                });
+    }
+
+    public void testDialogPlacedAboveParent() throws Exception {
+        doDialogTest("MatchParent",
+            (WindowState parent, WindowState dialog) -> {
+                // Not only should the dialog be higher, but it should be
+                // leave multiple layers of space inbetween for DimLayers,
+                // etc...
+                assertTrue(dialog.getLayer() - parent.getLayer() >= 5);
+        });
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/SurfaceViewTests.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/SurfaceViewTests.java
new file mode 100644
index 0000000..b929e98
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/SurfaceViewTests.java
@@ -0,0 +1,111 @@
+/*
+ * 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.server.cts;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.awt.Rectangle;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import android.server.cts.ActivityManagerTestBase;
+import android.server.cts.WindowManagerState.WindowState;
+
+public class SurfaceViewTests extends ActivityManagerTestBase {
+    static final String ACTIVITY_NAME = "SurfaceViewTestActivity";
+    static final String INTENT_KEY = "android.server.FrameTestApp.SurfaceViewTestCase";
+    static final String baseWindowName =
+        "android.server.FrameTestApp/android.server.FrameTestApp.";
+
+    private List<WindowState> mWindowList = new ArrayList();
+
+    public void startTestCase(String testCase) throws Exception{
+        setComponentName("android.server.FrameTestApp");
+        String cmd = getAmStartCmd(ACTIVITY_NAME, INTENT_KEY, testCase);
+        CLog.logAndDisplay(LogLevel.INFO, cmd);
+        executeShellCommand(cmd);
+    }
+
+    void stopTestCase() throws Exception{
+        executeShellCommand("am force-stop android.server.FrameTestApp");
+    }
+
+    WindowState getSingleWindow(String fullWindowName) {
+        try {
+            mAmWmState.getWmState().getMatchingWindowState(fullWindowName, mWindowList);
+            return mWindowList.get(0);
+        } catch (Exception e) {
+            CLog.logAndDisplay(LogLevel.INFO, "Couldn't find window: " + fullWindowName);
+            return null;
+        }
+    }
+
+    interface SurfaceViewTest {
+        void doTest(WindowState parent, WindowState surfaceView);
+    }
+
+    void doSurfaceViewTest(String testCase, SurfaceViewTest t) throws Exception {
+        startTestCase(testCase);
+
+        String svName = "SurfaceView - " + baseWindowName + ACTIVITY_NAME;
+        final String[] waitForVisible = new String[] { svName };
+
+        mAmWmState.computeState(mDevice, waitForVisible);
+        WindowState sv = getSingleWindow(svName);
+        WindowState parent = getSingleWindow(baseWindowName + "SurfaceViewTestActivity");
+
+        t.doTest(parent, sv);
+        stopTestCase();
+    }
+
+    public void testSurfaceViewOnBottom() throws Exception {
+        doSurfaceViewTest("OnBottom",
+            (WindowState parent, WindowState sv) -> {
+                assertFalse(sv.getLayer() >= parent.getLayer());
+            });
+    }
+
+    public void testSurfaceViewOnTop() throws Exception {
+        doSurfaceViewTest("OnTop",
+            (WindowState parent, WindowState sv) -> {
+                assertFalse(parent.getLayer() >= sv.getLayer());
+            });
+    }
+
+    public void testSurfaceViewOversized() throws Exception {
+        final int oversizedDimension = 8000;
+        doSurfaceViewTest("Oversized",
+            (WindowState parent, WindowState sv) -> {
+                    // The SurfaceView is allowed to be as big as it wants,
+                    // but we should verify it's visually cropped to the parent bounds.
+                    Rectangle parentFrame = parent.getFrame();
+                    Rectangle frame = sv.getFrame();
+                    assertEquals(oversizedDimension, frame.width);
+                    assertEquals(oversizedDimension, frame.height);
+
+                    Rectangle expectedCrop = new Rectangle(0, 0,
+                            parentFrame.width - frame.x,
+                            parentFrame.height - frame.y);
+                    assertEquals(expectedCrop, sv.getCrop());
+            });
+    }
+}
diff --git a/libs/deviceutil/Android.mk b/libs/deviceutil/Android.mk
index bb039ca..5682b64 100644
--- a/libs/deviceutil/Android.mk
+++ b/libs/deviceutil/Android.mk
@@ -22,7 +22,7 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test mockito-target
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/libs/deviceutil/src/android/cts/util/CtsKeyEventUtil.java b/libs/deviceutil/src/android/cts/util/CtsKeyEventUtil.java
new file mode 100644
index 0000000..dec71d7
--- /dev/null
+++ b/libs/deviceutil/src/android/cts/util/CtsKeyEventUtil.java
@@ -0,0 +1,293 @@
+/*
+ * 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.cts.util;
+
+import android.app.Instrumentation;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+
+import java.lang.reflect.Field;
+
+/**
+ * Utility class to send KeyEvents bypassing the IME. The code is similar to functions in
+ * {@link Instrumentation} and {@link android.test.InstrumentationTestCase} classes. It uses
+ * {@link InputMethodManager#dispatchKeyEventFromInputMethod(View, KeyEvent)} to send the events.
+ * After sending the events waits for idle.
+ */
+public final class CtsKeyEventUtil {
+
+    private CtsKeyEventUtil() {}
+
+    /**
+     * Sends the key events corresponding to the text to the app being instrumented.
+     *
+     * @param instrumentation the instrumentation used to run the test.
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param text The text to be sent. Null value returns immediately.
+     */
+    public static void sendString(final Instrumentation instrumentation, final View targetView,
+            final String text) {
+        if (text == null) {
+            return;
+        }
+
+        KeyEvent[] events = getKeyEvents(text);
+
+        if (events != null) {
+            for (int i = 0; i < events.length; i++) {
+                // We have to change the time of an event before injecting it because
+                // all KeyEvents returned by KeyCharacterMap.getEvents() have the same
+                // time stamp and the system rejects too old events. Hence, it is
+                // possible for an event to become stale before it is injected if it
+                // takes too long to inject the preceding ones.
+                sendKey(instrumentation, targetView, KeyEvent.changeTimeRepeat(
+                        events[i], SystemClock.uptimeMillis(), 0 /* newRepeat */));
+            }
+        }
+    }
+
+    /**
+     * Sends a series of key events through instrumentation. For instance:
+     * sendKeys(view, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_CENTER).
+     *
+     * @param instrumentation the instrumentation used to run the test.
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param keys The series of key codes.
+     */
+    public static void sendKeys(final Instrumentation instrumentation, final View targetView,
+            final int...keys) {
+        final int count = keys.length;
+
+        for (int i = 0; i < count; i++) {
+            try {
+                sendKeyDownUp(instrumentation, targetView, keys[i]);
+            } catch (SecurityException e) {
+                // Ignore security exceptions that are now thrown
+                // when trying to send to another app, to retain
+                // compatibility with existing tests.
+            }
+        }
+    }
+
+    /**
+     * Sends a series of key events through instrumentation. The sequence of keys is a string
+     * containing the key names as specified in KeyEvent, without the KEYCODE_ prefix. For
+     * instance: sendKeys(view, "DPAD_LEFT A B C DPAD_CENTER"). Each key can be repeated by using
+     * the N* prefix. For instance, to send two KEYCODE_DPAD_LEFT, use the following:
+     * sendKeys(view, "2*DPAD_LEFT").
+     *
+     * @param instrumentation the instrumentation used to run the test.
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param keysSequence The sequence of keys.
+     */
+    public static void sendKeys(final Instrumentation instrumentation, final View targetView,
+            final String keysSequence) {
+        final String[] keys = keysSequence.split(" ");
+        final int count = keys.length;
+
+        for (int i = 0; i < count; i++) {
+            String key = keys[i];
+            int repeater = key.indexOf('*');
+
+            int keyCount;
+            try {
+                keyCount = repeater == -1 ? 1 : Integer.parseInt(key.substring(0, repeater));
+            } catch (NumberFormatException e) {
+                Log.w("ActivityTestCase", "Invalid repeat count: " + key);
+                continue;
+            }
+
+            if (repeater != -1) {
+                key = key.substring(repeater + 1);
+            }
+
+            for (int j = 0; j < keyCount; j++) {
+                try {
+                    final Field keyCodeField = KeyEvent.class.getField("KEYCODE_" + key);
+                    final int keyCode = keyCodeField.getInt(null);
+                    try {
+                        sendKeyDownUp(instrumentation, targetView, keyCode);
+                    } catch (SecurityException e) {
+                        // Ignore security exceptions that are now thrown
+                        // when trying to send to another app, to retain
+                        // compatibility with existing tests.
+                    }
+                } catch (NoSuchFieldException e) {
+                    Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
+                    break;
+                } catch (IllegalAccessException e) {
+                    Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Sends an up and down key events.
+     *
+     * @param instrumentation the instrumentation used to run the test.
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param key The integer keycode for the event to be sent.
+     */
+    public static void sendKeyDownUp(final Instrumentation instrumentation, final View targetView,
+            final int key) {
+        sendKey(instrumentation, targetView, new KeyEvent(KeyEvent.ACTION_DOWN, key));
+        sendKey(instrumentation, targetView, new KeyEvent(KeyEvent.ACTION_UP, key));
+    }
+
+    /**
+     * Sends a key event.
+     *
+     * @param instrumentation the instrumentation used to run the test.
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param event KeyEvent to be send.
+     */
+    public static void sendKey(final Instrumentation instrumentation, final View targetView,
+            final KeyEvent event) {
+        validateNotAppThread();
+
+        long downTime = event.getDownTime();
+        long eventTime = event.getEventTime();
+        int action = event.getAction();
+        int code = event.getKeyCode();
+        int repeatCount = event.getRepeatCount();
+        int metaState = event.getMetaState();
+        int deviceId = event.getDeviceId();
+        int scanCode = event.getScanCode();
+        int source = event.getSource();
+        int flags = event.getFlags();
+        if (source == InputDevice.SOURCE_UNKNOWN) {
+            source = InputDevice.SOURCE_KEYBOARD;
+        }
+        if (eventTime == 0) {
+            eventTime = SystemClock.uptimeMillis();
+        }
+        if (downTime == 0) {
+            downTime = eventTime;
+        }
+
+        final KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount,
+                metaState, deviceId, scanCode, flags, source);
+
+        InputMethodManager imm = targetView.getContext().getSystemService(InputMethodManager.class);
+        imm.dispatchKeyEventFromInputMethod(null, newEvent);
+        instrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Sends a key event while holding another modifier key down, then releases both keys and
+     * waits for idle sync. Useful for sending combinations like shift + tab.
+     *
+     * @param instrumentation the instrumentation used to run the test.
+     * @param targetView View to find the ViewRootImpl and dispatch.
+     * @param keyCodeToSend The integer keycode for the event to be sent.
+     * @param modifierKeyCodeToHold The integer keycode of the modifier to be held.
+     */
+    public static void sendKeyWhileHoldingModifier(final Instrumentation instrumentation,
+            final View targetView, final int keyCodeToSend,
+            final int modifierKeyCodeToHold) {
+        final int metaState = getMetaStateForModifierKeyCode(modifierKeyCodeToHold);
+        final long downTime = SystemClock.uptimeMillis();
+
+        final KeyEvent holdKeyDown = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+                modifierKeyCodeToHold, 0 /* repeat */);
+        sendKey(instrumentation ,targetView, holdKeyDown);
+
+        final KeyEvent keyDown = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN,
+                keyCodeToSend, 0 /* repeat */, metaState);
+        sendKey(instrumentation, targetView, keyDown);
+
+        final KeyEvent keyUp = new KeyEvent(downTime, downTime, KeyEvent.ACTION_UP,
+                keyCodeToSend, 0 /* repeat */, metaState);
+        sendKey(instrumentation, targetView, keyUp);
+
+        final KeyEvent holdKeyUp = new KeyEvent(downTime, downTime, KeyEvent.ACTION_UP,
+                modifierKeyCodeToHold, 0 /* repeat */);
+        sendKey(instrumentation, targetView, holdKeyUp);
+
+        instrumentation.waitForIdleSync();
+    }
+
+    private static int getMetaStateForModifierKeyCode(int modifierKeyCode) {
+        if (!KeyEvent.isModifierKey(modifierKeyCode)) {
+            throw new IllegalArgumentException("Modifier key expected, but got: "
+                    + KeyEvent.keyCodeToString(modifierKeyCode));
+        }
+
+        int metaState;
+        switch (modifierKeyCode) {
+            case KeyEvent.KEYCODE_SHIFT_LEFT:
+                metaState = KeyEvent.META_SHIFT_LEFT_ON;
+                break;
+            case KeyEvent.KEYCODE_SHIFT_RIGHT:
+                metaState = KeyEvent.META_SHIFT_RIGHT_ON;
+                break;
+            case KeyEvent.KEYCODE_ALT_LEFT:
+                metaState = KeyEvent.META_ALT_LEFT_ON;
+                break;
+            case KeyEvent.KEYCODE_ALT_RIGHT:
+                metaState = KeyEvent.META_ALT_RIGHT_ON;
+                break;
+            case KeyEvent.KEYCODE_CTRL_LEFT:
+                metaState = KeyEvent.META_CTRL_LEFT_ON;
+                break;
+            case KeyEvent.KEYCODE_CTRL_RIGHT:
+                metaState = KeyEvent.META_CTRL_RIGHT_ON;
+                break;
+            case KeyEvent.KEYCODE_META_LEFT:
+                metaState = KeyEvent.META_META_LEFT_ON;
+                break;
+            case KeyEvent.KEYCODE_META_RIGHT:
+                metaState = KeyEvent.META_META_RIGHT_ON;
+                break;
+            case KeyEvent.KEYCODE_SYM:
+                metaState = KeyEvent.META_SYM_ON;
+                break;
+            case KeyEvent.KEYCODE_NUM:
+                metaState = KeyEvent.META_NUM_LOCK_ON;
+                break;
+            case KeyEvent.KEYCODE_FUNCTION:
+                metaState = KeyEvent.META_FUNCTION_ON;
+                break;
+            default:
+                // Safety net: all modifier keys need to have at least one meta state associated.
+                throw new UnsupportedOperationException("No meta state associated with "
+                        + "modifier key: " + KeyEvent.keyCodeToString(modifierKeyCode));
+        }
+
+        return KeyEvent.normalizeMetaState(metaState);
+    }
+
+    private static KeyEvent[] getKeyEvents(final String text) {
+        KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+        return keyCharacterMap.getEvents(text.toCharArray());
+    }
+
+    private static void validateNotAppThread() {
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            throw new RuntimeException(
+                    "This method can not be called from the main application thread");
+        }
+    }
+}
diff --git a/libs/deviceutil/src/android/cts/util/CtsTouchUtils.java b/libs/deviceutil/src/android/cts/util/CtsTouchUtils.java
new file mode 100644
index 0000000..6f1429c
--- /dev/null
+++ b/libs/deviceutil/src/android/cts/util/CtsTouchUtils.java
@@ -0,0 +1,307 @@
+/*
+ * 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.cts.util;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.os.SystemClock;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+/**
+ * Test utilities for touch emulation.
+ */
+public final class CtsTouchUtils {
+
+    private CtsTouchUtils() {}
+
+    /**
+     * Emulates a tap in the center of the passed {@link View}.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param view the view to "tap"
+     */
+    public static void emulateTapOnViewCenter(Instrumentation instrumentation, View view) {
+        emulateTapOnScreen(instrumentation, view, view.getWidth() / 2, view.getHeight() / 2);
+    }
+
+    /**
+     * Emulates a tap on a point relative to the top-left corner of the passed {@link View}. Offset
+     * parameters are used to compute the final screen coordinates of the tap point.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param anchorView the anchor view to determine the tap location on the screen
+     * @param offsetX extra X offset for the tap
+     * @param offsetY extra Y offset for the tap
+     */
+    public static void emulateTapOnScreen(Instrumentation instrumentation, View anchorView,
+            int offsetX, int offsetY) {
+        // Get anchor coordinates on the screen
+        final int[] viewOnScreenXY = new int[2];
+        anchorView.getLocationOnScreen(viewOnScreenXY);
+        int emulatedTapX = viewOnScreenXY[0] + offsetX;
+        int emulatedTapY = viewOnScreenXY[1] + offsetY;
+
+        // Inject DOWN event
+        long downTime = SystemClock.uptimeMillis();
+        MotionEvent eventDown = MotionEvent.obtain(
+                downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
+        instrumentation.sendPointerSync(eventDown);
+        eventDown.recycle();
+
+        // Inject MOVE event
+        long moveTime = SystemClock.uptimeMillis();
+        final int touchSlop = ViewConfiguration.get(anchorView.getContext()).getScaledTouchSlop();
+        MotionEvent eventMove = MotionEvent.obtain(downTime, moveTime, MotionEvent.ACTION_MOVE,
+                emulatedTapX + (touchSlop / 2.0f), emulatedTapY + (touchSlop / 2.0f), 1);
+        instrumentation.sendPointerSync(eventMove);
+        eventMove.recycle();
+
+        // Inject UP event
+        long upTime = SystemClock.uptimeMillis();
+        MotionEvent eventUp = MotionEvent.obtain(
+                upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
+        instrumentation.sendPointerSync(eventUp);
+        eventUp.recycle();
+
+        // Wait for the system to process all events in the queue
+        instrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Emulates a drag gesture across the screen.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param dragStartX Start X of the emulated drag gesture
+     * @param dragStartY Start Y of the emulated drag gesture
+     * @param dragAmountX X amount of the emulated drag gesture
+     * @param dragAmountY Y amount of the emulated drag gesture
+     */
+    public static void emulateDragGesture(Instrumentation instrumentation,
+            int dragStartX, int dragStartY, int dragAmountX, int dragAmountY) {
+        emulateDragGesture(instrumentation, dragStartX, dragStartY, dragAmountX, dragAmountY,
+                2000, 20);
+    }
+
+    private static void emulateDragGesture(Instrumentation instrumentation,
+            int dragStartX, int dragStartY, int dragAmountX, int dragAmountY,
+            int dragDurationMs, int moveEventCount) {
+        // We are using the UiAutomation object to inject events so that drag works
+        // across view / window boundaries (such as for the emulated drag and drop
+        // sequences)
+        final UiAutomation uiAutomation = instrumentation.getUiAutomation();
+
+        // Inject DOWN event
+        long downTime = SystemClock.uptimeMillis();
+        MotionEvent eventDown = MotionEvent.obtain(
+                downTime, downTime, MotionEvent.ACTION_DOWN, dragStartX, dragStartY, 1);
+        eventDown.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+        uiAutomation.injectInputEvent(eventDown, true);
+        eventDown.recycle();
+
+        // Inject a sequence of MOVE events that emulate the "move" part of the gesture
+        for (int i = 0; i < moveEventCount; i++) {
+            long moveTime = SystemClock.uptimeMillis();
+            // Note that we divide by (moveEventCount - 1) so that our last MOVE event is
+            // at the same coordinates as the subsequent UP event.
+            final int moveX = dragStartX + dragAmountX * i / (moveEventCount - 1);
+            final int moveY = dragStartY + dragAmountY * i / (moveEventCount - 1);
+            MotionEvent eventMove = MotionEvent.obtain(
+                    moveTime, moveTime, MotionEvent.ACTION_MOVE, moveX, moveY, 1);
+            eventMove.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+            uiAutomation.injectInputEvent(eventMove, true);
+            eventMove.recycle();
+            // sleep for a bit to emulate the overall swipe gesture
+            SystemClock.sleep(dragDurationMs / moveEventCount);
+        }
+
+        // Inject UP event
+        long upTime = SystemClock.uptimeMillis();
+        MotionEvent eventUp = MotionEvent.obtain(
+                upTime, upTime, MotionEvent.ACTION_UP, dragStartX + dragAmountX,
+                dragStartY + dragAmountY, 1);
+        eventUp.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+        uiAutomation.injectInputEvent(eventUp, true);
+        eventUp.recycle();
+
+        // Wait for the system to process all events in the queue
+        instrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Emulates a fling gesture across the horizontal center of the passed view.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param view the view to fling
+     * @param isDownwardsFlingGesture if <code>true</code>, the emulated fling will
+     *      be a downwards gesture
+     * @return The vertical amount of emulated fling in pixels
+     */
+    public static int emulateFlingGesture(Instrumentation instrumentation,
+            View view, boolean isDownwardsFlingGesture) {
+        final ViewConfiguration configuration = ViewConfiguration.get(view.getContext());
+        final int flingVelocity = (configuration.getScaledMinimumFlingVelocity() +
+                configuration.getScaledMaximumFlingVelocity()) / 2;
+        // Get view coordinates on the screen
+        final int[] viewOnScreenXY = new int[2];
+        view.getLocationOnScreen(viewOnScreenXY);
+
+        // Our fling gesture will be from 25% height of the view to 75% height of the view
+        // for downwards fling gesture, and the other way around for upwards fling gesture
+        final int viewHeight = view.getHeight();
+        final int x = viewOnScreenXY[0] + view.getWidth() / 2;
+        final int startY = isDownwardsFlingGesture ? viewOnScreenXY[1] + viewHeight / 4
+                : viewOnScreenXY[1] + 3 * viewHeight / 4;
+        final int amountY = isDownwardsFlingGesture ? viewHeight / 2 : -viewHeight / 2;
+
+        // Compute fling gesture duration based on the distance (50% height of the view) and
+        // fling velocity
+        final int durationMs = (1000 * viewHeight) / (2 * flingVelocity);
+
+        // And do the same event injection sequence as our generic drag gesture
+        emulateDragGesture(instrumentation, x, startY, 0, amountY, durationMs, 3);
+
+        return amountY;
+    }
+
+    private static class ViewStateSnapshot {
+        final View mFirst;
+        final View mLast;
+        final int mFirstTop;
+        final int mLastBottom;
+        final int mChildCount;
+        private ViewStateSnapshot(ViewGroup viewGroup) {
+            mChildCount = viewGroup.getChildCount();
+            if (mChildCount == 0) {
+                mFirst = mLast = null;
+                mFirstTop = mLastBottom = Integer.MIN_VALUE;
+            } else {
+                mFirst = viewGroup.getChildAt(0);
+                mLast = viewGroup.getChildAt(mChildCount - 1);
+                mFirstTop = mFirst.getTop();
+                mLastBottom = mLast.getBottom();
+            }
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            final ViewStateSnapshot that = (ViewStateSnapshot) o;
+            return mFirstTop == that.mFirstTop &&
+                    mLastBottom == that.mLastBottom &&
+                    mFirst == that.mFirst &&
+                    mLast == that.mLast &&
+                    mChildCount == that.mChildCount;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mFirst != null ? mFirst.hashCode() : 0;
+            result = 31 * result + (mLast != null ? mLast.hashCode() : 0);
+            result = 31 * result + mFirstTop;
+            result = 31 * result + mLastBottom;
+            result = 31 * result + mChildCount;
+            return result;
+        }
+    }
+
+    /**
+     * Emulates a scroll to the bottom of the specified {@link ViewGroup}.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param viewGroup View group
+     */
+    public static void emulateScrollToBottom(Instrumentation instrumentation, ViewGroup viewGroup) {
+        final int[] viewGroupOnScreenXY = new int[2];
+        viewGroup.getLocationOnScreen(viewGroupOnScreenXY);
+
+        final int emulatedX = viewGroupOnScreenXY[0] + viewGroup.getWidth() / 2;
+        final int emulatedStartY = viewGroupOnScreenXY[1] + 3 * viewGroup.getHeight() / 4;
+        final int swipeAmount = viewGroup.getHeight() / 2;
+
+        ViewStateSnapshot prev;
+        ViewStateSnapshot next = new ViewStateSnapshot(viewGroup);
+        do {
+            prev = next;
+            emulateDragGesture(instrumentation, emulatedX, emulatedStartY, 0, -swipeAmount,
+                    300, 10);
+            next = new ViewStateSnapshot(viewGroup);
+        } while (!prev.equals(next));
+    }
+
+    /**
+     * Emulates a long click in the center of the passed {@link View}.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param view the view to "long click"
+     */
+    public static void emulateLongClick(Instrumentation instrumentation, View view) {
+        emulateLongClick(instrumentation, view, 0);
+    }
+
+    /**
+     * Emulates a long click in the center of the passed {@link View}.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param view the view to "long click"
+     * @param extraWaitMs the duration of emulated long click in milliseconds starting
+     *      after system-level long press timeout.
+     */
+    public static void emulateLongClick(Instrumentation instrumentation, View view,
+            long extraWaitMs) {
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        final int[] viewOnScreenXY = new int[2];
+        view.getLocationOnScreen(viewOnScreenXY);
+        int emulatedTapX = viewOnScreenXY[0] + view.getWidth() / 2;
+        int emulatedTapY = viewOnScreenXY[1] + view.getHeight() / 2;
+
+        // Inject DOWN event
+        long downTime = SystemClock.uptimeMillis();
+        MotionEvent eventDown = MotionEvent.obtain(
+                downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
+        instrumentation.sendPointerSync(eventDown);
+        eventDown.recycle();
+
+        // Inject MOVE event
+        long moveTime = SystemClock.uptimeMillis();
+        MotionEvent eventMove = MotionEvent.obtain(
+                moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedTapX, emulatedTapY, 1);
+        instrumentation.sendPointerSync(eventMove);
+        eventMove.recycle();
+
+        SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout() * 1.5f) + extraWaitMs);
+
+        // Inject UP event
+        long upTime = SystemClock.uptimeMillis();
+        MotionEvent eventUp = MotionEvent.obtain(
+                upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
+        instrumentation.sendPointerSync(eventUp);
+        eventUp.recycle();
+
+        // Wait for the system to process all events in the queue
+        instrumentation.waitForIdleSync();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/FakeKeys.java b/libs/deviceutil/src/android/cts/util/FakeKeys.java
similarity index 99%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/FakeKeys.java
rename to libs/deviceutil/src/android/cts/util/FakeKeys.java
index 11df8e5..f3814a4 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/FakeKeys.java
+++ b/libs/deviceutil/src/android/cts/util/FakeKeys.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.deviceowner;
+package android.cts.util;
 
 // Copied from cts/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
 
diff --git a/libs/deviceutil/src/android/cts/util/KeyEventUtil.java b/libs/deviceutil/src/android/cts/util/KeyEventUtil.java
deleted file mode 100644
index b6d09d8..0000000
--- a/libs/deviceutil/src/android/cts/util/KeyEventUtil.java
+++ /dev/null
@@ -1,202 +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.cts.util;
-
-import android.app.Instrumentation;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.InputDevice;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-
-import java.lang.reflect.Field;
-
-/**
- * Utility class to send KeyEvents to TextView bypassing the IME. The code is similar to functions
- * in {@link Instrumentation} and {@link android.test.InstrumentationTestCase} classes. It uses
- * {@link InputMethodManager#dispatchKeyEventFromInputMethod(View, KeyEvent)} to send the events.
- * After sending the events waits for idle.
- */
-public class KeyEventUtil {
-    private final Instrumentation mInstrumentation;
-
-    public KeyEventUtil(Instrumentation instrumentation) {
-        this.mInstrumentation = instrumentation;
-    }
-
-    /**
-     * Sends the key events corresponding to the text to the app being instrumented.
-     *
-     * @param targetView View to find the ViewRootImpl and dispatch.
-     * @param text The text to be sent. Null value returns immediately.
-     */
-    public final void sendString(final View targetView, final String text) {
-        if (text == null) {
-            return;
-        }
-
-        KeyEvent[] events = getKeyEvents(text);
-
-        if (events != null) {
-            for (int i = 0; i < events.length; i++) {
-                // We have to change the time of an event before injecting it because
-                // all KeyEvents returned by KeyCharacterMap.getEvents() have the same
-                // time stamp and the system rejects too old events. Hence, it is
-                // possible for an event to become stale before it is injected if it
-                // takes too long to inject the preceding ones.
-                sendKey(targetView, KeyEvent.changeTimeRepeat(events[i], SystemClock.uptimeMillis(),
-                        0));
-            }
-        }
-    }
-
-    /**
-     * Sends a series of key events through instrumentation. For instance:
-     * sendKeys(view, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_CENTER).
-     *
-     * @param targetView View to find the ViewRootImpl and dispatch.
-     * @param keys The series of key codes.
-     */
-    public final void sendKeys(final View targetView, final int...keys) {
-        final int count = keys.length;
-
-        for (int i = 0; i < count; i++) {
-            try {
-                sendKeyDownUp(targetView, keys[i]);
-            } catch (SecurityException e) {
-                // Ignore security exceptions that are now thrown
-                // when trying to send to another app, to retain
-                // compatibility with existing tests.
-            }
-        }
-    }
-
-    /**
-     * Sends a series of key events through instrumentation. The sequence of keys is a string
-     * containing the key names as specified in KeyEvent, without the KEYCODE_ prefix. For
-     * instance: sendKeys(view, "DPAD_LEFT A B C DPAD_CENTER"). Each key can be repeated by using
-     * the N* prefix. For instance, to send two KEYCODE_DPAD_LEFT, use the following:
-     * sendKeys(view, "2*DPAD_LEFT").
-     *
-     * @param targetView View to find the ViewRootImpl and dispatch.
-     * @param keysSequence The sequence of keys.
-     */
-    public final void sendKeys(final View targetView, final String keysSequence) {
-        final String[] keys = keysSequence.split(" ");
-        final int count = keys.length;
-
-        for (int i = 0; i < count; i++) {
-            String key = keys[i];
-            int repeater = key.indexOf('*');
-
-            int keyCount;
-            try {
-                keyCount = repeater == -1 ? 1 : Integer.parseInt(key.substring(0, repeater));
-            } catch (NumberFormatException e) {
-                Log.w("ActivityTestCase", "Invalid repeat count: " + key);
-                continue;
-            }
-
-            if (repeater != -1) {
-                key = key.substring(repeater + 1);
-            }
-
-            for (int j = 0; j < keyCount; j++) {
-                try {
-                    final Field keyCodeField = KeyEvent.class.getField("KEYCODE_" + key);
-                    final int keyCode = keyCodeField.getInt(null);
-                    try {
-                        sendKeyDownUp(targetView, keyCode);
-                    } catch (SecurityException e) {
-                        // Ignore security exceptions that are now thrown
-                        // when trying to send to another app, to retain
-                        // compatibility with existing tests.
-                    }
-                } catch (NoSuchFieldException e) {
-                    Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
-                    break;
-                } catch (IllegalAccessException e) {
-                    Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
-                    break;
-                }
-            }
-        }
-    }
-
-    /**
-     * Sends an up and down key events.
-     *
-     * @param targetView View to find the ViewRootImpl and dispatch.
-     * @param key The integer keycode for the event to be send.
-     */
-    public final void sendKeyDownUp(final View targetView, final int key) {
-        sendKey(targetView, new KeyEvent(KeyEvent.ACTION_DOWN, key));
-        sendKey(targetView, new KeyEvent(KeyEvent.ACTION_UP, key));
-    }
-
-    /**
-     * Sends a key event.
-     *
-     * @param targetView View to find the ViewRootImpl and dispatch.
-     * @param event KeyEvent to be send.
-     */
-    public final void sendKey(final View targetView, final KeyEvent event) {
-        validateNotAppThread();
-
-        long downTime = event.getDownTime();
-        long eventTime = event.getEventTime();
-        int action = event.getAction();
-        int code = event.getKeyCode();
-        int repeatCount = event.getRepeatCount();
-        int metaState = event.getMetaState();
-        int deviceId = event.getDeviceId();
-        int scancode = event.getScanCode();
-        int source = event.getSource();
-        int flags = event.getFlags();
-        if (source == InputDevice.SOURCE_UNKNOWN) {
-            source = InputDevice.SOURCE_KEYBOARD;
-        }
-        if (eventTime == 0) {
-            eventTime = SystemClock.uptimeMillis();
-        }
-        if (downTime == 0) {
-            downTime = eventTime;
-        }
-
-        final KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount,
-                metaState, deviceId, scancode, flags, source);
-
-        InputMethodManager imm = targetView.getContext().getSystemService(InputMethodManager.class);
-        imm.dispatchKeyEventFromInputMethod(null, newEvent);
-        mInstrumentation.waitForIdleSync();
-    }
-
-    private KeyEvent[] getKeyEvents(final String text) {
-        KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
-        return keyCharacterMap.getEvents(text.toCharArray());
-    }
-
-    private void validateNotAppThread() {
-        if (Looper.myLooper() == Looper.getMainLooper()) {
-            throw new RuntimeException(
-                    "This method can not be called from the main application thread");
-        }
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/PollingCheck.java b/libs/deviceutil/src/android/cts/util/PollingCheck.java
index 3a08c7e..0e255a1 100644
--- a/libs/deviceutil/src/android/cts/util/PollingCheck.java
+++ b/libs/deviceutil/src/android/cts/util/PollingCheck.java
@@ -82,4 +82,13 @@
             }
         }.run();
     }
+
+    public static void waitFor(long timeout, final PollingCheckCondition condition) {
+        new PollingCheck(timeout) {
+            @Override
+            protected boolean check() {
+                return condition.canProceed();
+            }
+        }.run();
+    }
 }
diff --git a/libs/deviceutil/src/android/cts/util/WidgetTestUtils.java b/libs/deviceutil/src/android/cts/util/WidgetTestUtils.java
index 813672e..a1197cc 100644
--- a/libs/deviceutil/src/android/cts/util/WidgetTestUtils.java
+++ b/libs/deviceutil/src/android/cts/util/WidgetTestUtils.java
@@ -16,27 +16,42 @@
 
 package android.cts.util;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
+import android.app.Instrumentation;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-
-import java.io.IOException;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewTreeObserver;
 
 import junit.framework.Assert;
 
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static android.view.ViewTreeObserver.*;
+import static org.mockito.Matchers.*;
+
 /**
  * The useful methods for widget test.
  */
 public class WidgetTestUtils {
     /**
-     * Assert that two bitmaps are equal.
+     * Assert that two bitmaps have identical content (same dimensions, same configuration,
+     * same pixel content).
      *
-     * @param Bitmap b1 the first bitmap which needs to compare.
-     * @param Bitmap b2 the second bitmap which needs to compare.
+     * @param b1 the first bitmap which needs to compare.
+     * @param b2 the second bitmap which needs to compare.
      */
     public static void assertEquals(Bitmap b1, Bitmap b2) {
         if (b1 == b2) {
@@ -135,4 +150,94 @@
         options.inPreferredConfig = config;
         return BitmapFactory.decodeResource(resources, resId, options);
     }
+
+    /**
+     * Argument matcher for equality check of a CharSequence.
+     *
+     * @param expected expected CharSequence
+     *
+     * @return
+     */
+    public static CharSequence sameCharSequence(final CharSequence expected) {
+        return argThat(new BaseMatcher<CharSequence>() {
+            @Override
+            public boolean matches(Object o) {
+                if (o instanceof CharSequence) {
+                    return TextUtils.equals(expected, (CharSequence) o);
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("doesn't match " + expected);
+            }
+        });
+    }
+
+    /**
+     * Argument matcher for equality check of an Editable.
+     *
+     * @param expected expected Editable
+     *
+     * @return
+     */
+    public static Editable sameEditable(final Editable expected) {
+        return argThat(new BaseMatcher<Editable>() {
+            @Override
+            public boolean matches(Object o) {
+                if (o instanceof Editable) {
+                    return TextUtils.equals(expected, (Editable) o);
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("doesn't match " + expected);
+            }
+        });
+    }
+
+    /**
+     * Runs the specified Runnable on the main thread and ensures that the specified View's tree is
+     * drawn before returning.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param view the view whose tree should be drawn before returning
+     * @param runner the runnable to run on the main thread, or {@code null} to
+     *               simply force invalidation and a draw pass
+     */
+    public static void runOnMainAndDrawSync(@NonNull Instrumentation instrumentation,
+                                            @NonNull final View view,
+                                            @Nullable final Runnable runner) {
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        instrumentation.runOnMainSync(() -> {
+            final ViewTreeObserver observer = view.getViewTreeObserver();
+            final OnDrawListener listener = new OnDrawListener() {
+                @Override
+                public void onDraw() {
+                    observer.removeOnDrawListener(this);
+                    view.post(() -> latch.countDown());
+                }
+            };
+
+            observer.addOnDrawListener(listener);
+
+            if (runner != null) {
+                runner.run();
+            } else {
+                view.invalidate();
+            }
+        });
+
+        try {
+            Assert.assertTrue("Expected draw pass occurred within 5 seconds",
+                    latch.await(5, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
 }
diff --git a/tests/app/Android.mk b/tests/app/Android.mk
index 775e679..6ce0148 100644
--- a/tests/app/Android.mk
+++ b/tests/app/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common voip-common org.apache.http.legacy
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver mockito-target android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 10a6792..4057aa0 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -196,7 +196,7 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="android.app.stubs.ChildTabActivity" android:label="ChildTabActivity" />
+        <activity android:name="android.app.stubs.FragmentResultActivity" android:label="FragmentResultActivity" />
 
         <activity android:name="android.app.stubs.LauncherActivityStub"
                   android:label="LauncherActivityStub" >
@@ -329,6 +329,9 @@
 
         <activity android:name="android.app.stubs.KeyboardShortcutsActivity" />
 
+        <activity android:name="android.app.stubs.NewDocumentTestActivity"
+                  android:documentLaunchMode="intoExisting" />
+
     </application>
 
 </manifest>
diff --git a/tests/app/app/src/android/app/stubs/ChildTabActivity.java b/tests/app/app/src/android/app/stubs/ChildTabActivity.java
deleted file mode 100644
index 1f0fb37..0000000
--- a/tests/app/app/src/android/app/stubs/ChildTabActivity.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.stubs;
-
-import android.app.Activity;
-
-/**
- * An empty activity for the TabActivity test
- */
-public class ChildTabActivity extends Activity {
-}
diff --git a/tests/app/app/src/android/app/stubs/FragmentResultActivity.java b/tests/app/app/src/android/app/stubs/FragmentResultActivity.java
new file mode 100644
index 0000000..364d093
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/FragmentResultActivity.java
@@ -0,0 +1,39 @@
+/*
+ * 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.app.stubs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * A simple Activity used to return a result.
+ */
+public class FragmentResultActivity extends Activity {
+    public static final String EXTRA_RESULT_CODE = "result";
+    public static final String EXTRA_RESULT_CONTENT = "result_content";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        int resultCode = getIntent().getIntExtra(EXTRA_RESULT_CODE, Activity.RESULT_OK);
+        String result = getIntent().getStringExtra(EXTRA_RESULT_CONTENT);
+        Intent intent = new Intent();
+        intent.putExtra(EXTRA_RESULT_CONTENT, result);
+        setResult(resultCode, intent);
+        finish();
+    }
+}
diff --git a/tests/app/app/src/android/app/stubs/FragmentTestActivity.java b/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
index a421895..a5f54bc 100644
--- a/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
+++ b/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.Fragment;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
 import android.transition.Transition;
 import android.transition.Transition.TransitionListener;
diff --git a/tests/app/app/src/android/app/stubs/MockTabActivity.java b/tests/app/app/src/android/app/stubs/MockTabActivity.java
index 247cfe0..722ac69 100644
--- a/tests/app/app/src/android/app/stubs/MockTabActivity.java
+++ b/tests/app/app/src/android/app/stubs/MockTabActivity.java
@@ -40,7 +40,7 @@
         final TabHost tabHost = getTabHost();
 
         tabHost.addTab(tabHost.newTabSpec(TAB1).setIndicator(TAB1)
-                .setContent(new Intent(this, ChildTabActivity.class)));
+                .setContent(new Intent(this, MockActivity.class)));
 
         tabHost.addTab(tabHost.newTabSpec(TAB2).setIndicator(TAB2)
                 .setContent(new Intent(this, MockActivity.class)));
diff --git a/tests/app/app/src/android/app/stubs/NewDocumentTestActivity.java b/tests/app/app/src/android/app/stubs/NewDocumentTestActivity.java
new file mode 100644
index 0000000..b12d969
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/NewDocumentTestActivity.java
@@ -0,0 +1,36 @@
+/*
+ * 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.app.stubs;
+
+import android.app.Activity;
+import android.content.Intent;
+
+public class NewDocumentTestActivity extends Activity {
+    public static final String NOTIFY_RESUME = "android.app.stubs.NOTIFY_RESUME";
+    public static final String NOTIFY_NEW_INTENT = "android.app.stubs.NOTIFY_NEW_INTENT";
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        sendBroadcast(new Intent(NOTIFY_RESUME));
+    }
+
+    @Override
+    public void onNewIntent(Intent intent) {
+        sendBroadcast(new Intent(NOTIFY_NEW_INTENT));
+    }
+}
diff --git a/tests/app/src/android/app/cts/ActivityActionModeTest.java b/tests/app/src/android/app/cts/ActivityActionModeTest.java
new file mode 100644
index 0000000..b74e737
--- /dev/null
+++ b/tests/app/src/android/app/cts/ActivityActionModeTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.app.cts;
+
+import static org.mockito.Mockito.*;
+
+import android.app.stubs.MockActivity;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.ActionMode;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ActivityActionModeTest {
+
+    private ActionMode.Callback mCallback;
+
+    @Rule
+    public ActivityTestRule<MockActivity> mActivityRule =
+            new ActivityTestRule<>(MockActivity.class);
+
+    @Before
+    public void setUp() {
+        mCallback = mock(ActionMode.Callback.class);
+        when(mCallback.onCreateActionMode(any(), any())).thenReturn(true);
+        when(mCallback.onPrepareActionMode(any(), any())).thenReturn(true);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testStartPrimaryActionMode() {
+        final ActionMode mode = mActivityRule.getActivity().startActionMode(
+                mCallback, ActionMode.TYPE_PRIMARY);
+
+        assertNotNull(mode);
+        assertEquals(ActionMode.TYPE_PRIMARY, mode.getType());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testStartFloatingActionMode() {
+        final ActionMode mode = mActivityRule.getActivity().startActionMode(
+                mCallback, ActionMode.TYPE_FLOATING);
+
+        assertNotNull(mode);
+        assertEquals(ActionMode.TYPE_FLOATING, mode.getType());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testStartTypelessActionMode() {
+        final ActionMode mode = mActivityRule.getActivity().startActionMode(mCallback);
+
+        assertNotNull(mode);
+        assertEquals(ActionMode.TYPE_PRIMARY, mode.getType());
+    }
+}
diff --git a/tests/app/src/android/app/cts/FragmentReceiveResultTest.java b/tests/app/src/android/app/cts/FragmentReceiveResultTest.java
new file mode 100644
index 0000000..f20113b
--- /dev/null
+++ b/tests/app/src/android/app/cts/FragmentReceiveResultTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.app.cts;
+
+import static org.mockito.Mockito.*;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.PendingIntent;
+import android.app.stubs.FragmentResultActivity;
+import android.app.stubs.FragmentTestActivity;
+import android.app.stubs.R;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.mockito.ArgumentCaptor;
+
+/**
+ * Tests Fragment's startActivityForResult and startIntentSenderForResult.
+ */
+public class FragmentReceiveResultTest extends
+        ActivityInstrumentationTestCase2<FragmentTestActivity> {
+
+    private FragmentTestActivity mActivity;
+    private Fragment mFragment;
+
+    public FragmentReceiveResultTest() {
+        super(FragmentTestActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mFragment = attachTestFragment();
+    }
+
+    @SmallTest
+    public void testStartActivityForResultOk() {
+        startActivityForResult(10, Activity.RESULT_OK, "content 10");
+
+        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+        verify(mFragment, times(1))
+                .onActivityResult(eq(10), eq(Activity.RESULT_OK), captor.capture());
+        final String data = captor.getValue()
+                .getStringExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT);
+        assertEquals("content 10", data);
+    }
+
+    @SmallTest
+    public void testStartActivityForResultCanceled() {
+        startActivityForResult(20, Activity.RESULT_CANCELED, "content 20");
+
+        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+        verify(mFragment, times(1))
+                .onActivityResult(eq(20), eq(Activity.RESULT_CANCELED), captor.capture());
+        final String data = captor.getValue()
+                .getStringExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT);
+        assertEquals("content 20", data);
+    }
+
+    @SmallTest
+    public void testStartIntentSenderForResultOk() {
+        startIntentSenderForResult(30, Activity.RESULT_OK, "content 30");
+
+        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+        verify(mFragment, times(1))
+                .onActivityResult(eq(30), eq(Activity.RESULT_OK), captor.capture());
+        final String data = captor.getValue()
+                .getStringExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT);
+        assertEquals("content 30", data);
+    }
+
+    @SmallTest
+    public void testStartIntentSenderForResultCanceled() {
+        startIntentSenderForResult(40, Activity.RESULT_CANCELED, "content 40");
+
+        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+        verify(mFragment, times(1))
+                .onActivityResult(eq(40), eq(Activity.RESULT_CANCELED), captor.capture());
+        final String data = captor.getValue()
+                .getStringExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT);
+        assertEquals("content 40", data);
+    }
+
+    private Fragment attachTestFragment() {
+        final Fragment fragment = spy(new Fragment());
+        getInstrumentation().waitForIdleSync();
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.getFragmentManager().beginTransaction()
+                        .add(R.id.content, fragment)
+                        .addToBackStack(null)
+                        .commitAllowingStateLoss();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        return fragment;
+    }
+
+    private void startActivityForResult(final int requestCode, final int resultCode,
+            final String content) {
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                Intent intent = new Intent(mActivity, FragmentResultActivity.class);
+                intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CODE, resultCode);
+                intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT, content);
+
+                mFragment.startActivityForResult(intent, requestCode);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+
+    private void startIntentSenderForResult(final int requestCode, final int resultCode,
+            final String content) {
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                Intent intent = new Intent(mActivity, FragmentResultActivity.class);
+                intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CODE, resultCode);
+                intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT, content);
+
+                PendingIntent pendingIntent = PendingIntent.getActivity(mActivity,
+                        requestCode, intent, 0);
+
+                try {
+                    mFragment.startIntentSenderForResult(pendingIntent.getIntentSender(),
+                            requestCode, null, 0, 0, 0, null);
+                } catch (IntentSender.SendIntentException e) {
+                    fail("IntentSender failed");
+                }
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+
+}
diff --git a/tests/app/src/android/app/cts/FragmentTransactionTest.java b/tests/app/src/android/app/cts/FragmentTransactionTest.java
new file mode 100644
index 0000000..2ff69a7
--- /dev/null
+++ b/tests/app/src/android/app/cts/FragmentTransactionTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.app.cts;
+
+import android.app.Fragment;
+import android.app.stubs.FragmentTestActivity;
+import android.app.stubs.R;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.TestCase.*;
+
+/**
+ * Tests usage of the {@link android.app.FragmentTransaction} class.
+ */
+@RunWith(AndroidJUnit4.class)
+public class FragmentTransactionTest {
+
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<>(FragmentTestActivity.class);
+
+    private FragmentTestActivity mActivity;
+
+    @Before
+    public void setUp() {
+        mActivity = mActivityRule.getActivity();
+    }
+
+    @Test
+    public void testAddTransactionWithValidFragment() {
+        final Fragment fragment = new CorrectFragment();
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.getFragmentManager().beginTransaction()
+                        .add(R.id.content, fragment)
+                        .addToBackStack(null)
+                        .commit();
+                mActivity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        assertTrue(fragment.isAdded());
+    }
+
+    @Test
+    public void testAddTransactionWithPrivateFragment() {
+        final Fragment fragment = new PrivateFragment();
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                boolean exceptionThrown = false;
+                try {
+                    mActivity.getFragmentManager().beginTransaction()
+                            .add(R.id.content, fragment)
+                            .addToBackStack(null)
+                            .commit();
+                    mActivity.getFragmentManager().executePendingTransactions();
+                } catch (IllegalStateException e) {
+                    exceptionThrown = true;
+                } finally {
+                    assertTrue("Exception should be thrown", exceptionThrown);
+                    assertFalse("Fragment shouldn't be added", fragment.isAdded());
+                }
+            }
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testAddTransactionWithPackagePrivateFragment() {
+        final Fragment fragment = new PackagePrivateFragment();
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                boolean exceptionThrown = false;
+                try {
+                    mActivity.getFragmentManager().beginTransaction()
+                            .add(R.id.content, fragment)
+                            .addToBackStack(null)
+                            .commit();
+                    mActivity.getFragmentManager().executePendingTransactions();
+                } catch (IllegalStateException e) {
+                    exceptionThrown = true;
+                } finally {
+                    assertTrue("Exception should be thrown", exceptionThrown);
+                    assertFalse("Fragment shouldn't be added", fragment.isAdded());
+                }
+            }
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testAddTransactionWithAnonymousFragment() {
+        final Fragment fragment = new Fragment() {};
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                boolean exceptionThrown = false;
+                try {
+                    mActivity.getFragmentManager().beginTransaction()
+                            .add(R.id.content, fragment)
+                            .addToBackStack(null)
+                            .commit();
+                    mActivity.getFragmentManager().executePendingTransactions();
+                } catch (IllegalStateException e) {
+                    exceptionThrown = true;
+                } finally {
+                    assertTrue("Exception should be thrown", exceptionThrown);
+                    assertFalse("Fragment shouldn't be added", fragment.isAdded());
+                }
+            }
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    @Test
+    public void testAddTransactionWithNonStaticFragment() {
+        final Fragment fragment = new NonStaticFragment();
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                boolean exceptionThrown = false;
+                try {
+                    mActivity.getFragmentManager().beginTransaction()
+                            .add(R.id.content, fragment)
+                            .addToBackStack(null)
+                            .commit();
+                    mActivity.getFragmentManager().executePendingTransactions();
+                } catch (IllegalStateException e) {
+                    exceptionThrown = true;
+                } finally {
+                    assertTrue("Exception should be thrown", exceptionThrown);
+                    assertFalse("Fragment shouldn't be added", fragment.isAdded());
+                }
+            }
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    public static class CorrectFragment extends Fragment {}
+
+    private static class PrivateFragment extends Fragment {}
+
+    private static class PackagePrivateFragment extends Fragment {}
+
+    private class NonStaticFragment extends Fragment {}
+}
diff --git a/tests/app/src/android/app/cts/NewDocumentTest.java b/tests/app/src/android/app/cts/NewDocumentTest.java
new file mode 100644
index 0000000..52d8df9
--- /dev/null
+++ b/tests/app/src/android/app/cts/NewDocumentTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.app.cts;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import android.app.stubs.NewDocumentTestActivity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.test.AndroidTestCase;
+
+public class NewDocumentTest extends AndroidTestCase {
+    private static Uri TEST_URI = Uri.parse("test_uri");
+    private static long TIMEOUT_MS = 3000;
+
+    public void testNewDocument() throws InterruptedException {
+        final Intent intent = new Intent();
+        intent.setClass(getContext(), NewDocumentTestActivity.class);
+        intent.setData(TEST_URI);
+
+        try (final Receiver receiver = new Receiver(NewDocumentTestActivity.NOTIFY_RESUME)) {
+            getContext().startActivity(intent);
+            receiver.await();
+        }
+
+        try (final Receiver receiver = new Receiver(NewDocumentTestActivity.NOTIFY_NEW_INTENT)) {
+            getContext().startActivity(intent);
+            receiver.await();
+        }
+    }
+
+    private class Receiver extends BroadcastReceiver implements AutoCloseable {
+        private final CountDownLatch latch = new CountDownLatch(1);
+
+        Receiver(String action) {
+            getContext().registerReceiver(this, new IntentFilter(action));
+        }
+
+        void await() throws InterruptedException {
+            assertTrue(
+                    "Timeout for broadcast from activity",
+                    latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            latch.countDown();
+        }
+
+        @Override
+        public void close() {
+            getContext().unregisterReceiver(this);
+        }
+    }
+}
diff --git a/tests/aslr/src/AslrMallocTest.cpp b/tests/aslr/src/AslrMallocTest.cpp
index 6e773cb..91a36e2 100644
--- a/tests/aslr/src/AslrMallocTest.cpp
+++ b/tests/aslr/src/AslrMallocTest.cpp
@@ -157,7 +157,9 @@
             return EXIT_FAILURE;
         }
 
-        printf("%p", malloc(size));
+        void* p = malloc(size);
+        printf("%p", p);
+        free(p);
         return EXIT_SUCCESS;
     }
 #endif
diff --git a/tests/camera/libctscamera2jni/native-camera-jni.cpp b/tests/camera/libctscamera2jni/native-camera-jni.cpp
index db687bf..4a3620e 100644
--- a/tests/camera/libctscamera2jni/native-camera-jni.cpp
+++ b/tests/camera/libctscamera2jni/native-camera-jni.cpp
@@ -345,7 +345,7 @@
 
 class StaticInfo {
   public:
-    StaticInfo(ACameraMetadata* chars) : mChars(chars) {}
+    explicit StaticInfo(ACameraMetadata* chars) : mChars(chars) {}
 
     bool isColorOutputSupported() {
         return isCapabilitySupported(ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 60a461c..26fd83e 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -237,19 +237,6 @@
   bug: 23779168
 },
 {
-  description: "New assist tests that do not yet have a track record.",
-  names: [
-    "android.assist.cts.AssistantContentViewTest",
-    "android.assist.cts.ExtraAssistDataTest",
-    "android.assist.cts.FocusChangeTest",
-    "android.assist.cts.LargeViewHierarchyTest",
-    "android.assist.cts.ScreenshotTest",
-    "android.assist.cts.TextViewTest",
-    "android.assist.cts.WebViewTest"
-  ],
-  bug: 21668302
-},
-{
   description: "ConnectivityConstraintTest job scheduler not working.",
   names: [
      "android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withWifi",
diff --git a/tests/fragment/res/layout/double_container.xml b/tests/fragment/res/layout/double_container.xml
new file mode 100644
index 0000000..c24d5ce
--- /dev/null
+++ b/tests/fragment/res/layout/double_container.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <FrameLayout
+        android:id="@+id/fragmentContainer1"
+        android:layout_weight="1"
+        android:layout_width="match_parent"
+        android:layout_height="0px"/>
+    <FrameLayout
+        android:id="@+id/fragmentContainer2"
+        android:layout_weight="1"
+        android:layout_width="match_parent"
+        android:layout_height="0px"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/fragment/res/layout/simple_container.xml b/tests/fragment/res/layout/simple_container.xml
new file mode 100644
index 0000000..f231c1ec
--- /dev/null
+++ b/tests/fragment/res/layout/simple_container.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:id="@+id/fragmentContainer"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent">
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
new file mode 100644
index 0000000..2d75395
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
@@ -0,0 +1,296 @@
+/*
+ * 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.fragment.cts;
+
+import static junit.framework.Assert.*;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.Instrumentation;
+import android.os.Debug;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class FragmentAnimatorTest {
+    // These are pretend resource IDs for animators. We don't need real ones since we
+    // load them by overriding onCreateAnimator
+    private final static int ENTER = 1;
+    private final static int EXIT = 2;
+    private final static int POP_ENTER = 3;
+    private final static int POP_EXIT = 4;
+
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setupContainer() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+    }
+
+    // Ensure that adding and popping a Fragment uses the enter and popExit animators
+    @Test
+    public void addAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .add(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertEnterPopExit(fragment);
+    }
+
+    // Ensure that removing and popping a Fragment uses the exit and popEnter animators
+    @Test
+    public void removeAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment, "1").commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .remove(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertExitPopEnter(fragment);
+    }
+
+    // Ensure that showing and popping a Fragment uses the enter and popExit animators
+    @Test
+    public void showAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .show(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertEnterPopExit(fragment);
+    }
+
+    // Ensure that hiding and popping a Fragment uses the exit and popEnter animators
+    @Test
+    public void hideAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment, "1").commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .hide(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertExitPopEnter(fragment);
+    }
+
+    // Ensure that attaching and popping a Fragment uses the enter and popExit animators
+    @Test
+    public void attachAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment).detach(fragment).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .attach(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertEnterPopExit(fragment);
+    }
+
+    // Ensure that detaching and popping a Fragment uses the exit and popEnter animators
+    @Test
+    public void detachAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment, "1").commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .detach(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertExitPopEnter(fragment);
+    }
+
+    // Replace should exit the existing fragments and enter the added fragment, then
+    // popping should popExit the removed fragment and popEnter the added fragments
+    @Test
+    public void replaceAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final AnimatorFragment fragment1 = new AnimatorFragment();
+        final AnimatorFragment fragment2 = new AnimatorFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .add(R.id.fragmentContainer, fragment2, "2")
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        final AnimatorFragment fragment3 = new AnimatorFragment();
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .replace(R.id.fragmentContainer, fragment3)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertFragmentAnimation(fragment1, 1, false, EXIT);
+        assertFragmentAnimation(fragment2, 1, false, EXIT);
+        assertFragmentAnimation(fragment3, 1, true, ENTER);
+
+        mInstrumentation.waitForIdleSync();
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertFragmentAnimation(fragment3, 2, false, POP_EXIT);
+        final AnimatorFragment replacement1 = (AnimatorFragment) fm.findFragmentByTag("1");
+        final AnimatorFragment replacement2 = (AnimatorFragment) fm.findFragmentByTag("1");
+        int expectedAnimations = replacement1 == fragment1 ? 2 : 1;
+        assertFragmentAnimation(replacement1, expectedAnimations, true, POP_ENTER);
+        assertFragmentAnimation(replacement2, expectedAnimations, true, POP_ENTER);
+    }
+
+    private void assertEnterPopExit(AnimatorFragment fragment) throws Throwable {
+        assertFragmentAnimation(fragment, 1, true, ENTER);
+        mInstrumentation.waitForIdleSync();
+
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertFragmentAnimation(fragment, 2, false, POP_EXIT);
+    }
+
+    private void assertExitPopEnter(AnimatorFragment fragment) throws Throwable {
+        assertFragmentAnimation(fragment, 1, false, EXIT);
+        mInstrumentation.waitForIdleSync();
+
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        AnimatorFragment replacement = (AnimatorFragment) fm.findFragmentByTag("1");
+
+        boolean isSameFragment = replacement == fragment;
+        int expectedAnimators = isSameFragment ? 2 : 1;
+        assertFragmentAnimation(replacement, expectedAnimators, true, POP_ENTER);
+    }
+
+    private void assertFragmentAnimation(AnimatorFragment fragment, int numAnimators,
+            boolean isEnter, int animatorResourceId) throws InterruptedException {
+        assertEquals(numAnimators, fragment.numAnimators);
+        assertEquals(isEnter, fragment.enter);
+        assertEquals(animatorResourceId, fragment.resourceId);
+        assertNotNull(fragment.animator);
+        assertTrue(fragment.wasStarted);
+        assertTrue(fragment.endLatch.await(100, TimeUnit.MILLISECONDS));
+    }
+
+    public static class AnimatorFragment extends StrictViewFragment {
+        int numAnimators;
+        Animator animator;
+        boolean enter;
+        int resourceId;
+        boolean wasStarted;
+        CountDownLatch endLatch;
+
+        @Override
+        public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
+            if (nextAnim == 0) {
+                return null;
+            }
+            this.numAnimators++;
+            this.wasStarted = false;
+            this.animator = ValueAnimator.ofFloat(0, 1).setDuration(1);
+            this.endLatch = new CountDownLatch(1);
+            this.animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    wasStarted = true;
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    endLatch.countDown();
+                }
+            });
+            this.resourceId = nextAnim;
+            this.enter = enter;
+            return this.animator;
+        }
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
new file mode 100644
index 0000000..c83d4fa
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
@@ -0,0 +1,44 @@
+/*
+ * 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.fragment.cts;
+
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+
+public class FragmentTestUtil {
+    public static void executePendingTransactions(final ActivityTestRule<FragmentTestActivity> rule)
+            throws Throwable {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                rule.getActivity().getFragmentManager().executePendingTransactions();
+            }
+        });
+    }
+
+    public static void setContentView(final ActivityTestRule<FragmentTestActivity> rule,
+            final int layoutId) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                rule.getActivity().setContentView(layoutId);
+            }
+        });
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
new file mode 100644
index 0000000..ef28a1d
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
@@ -0,0 +1,770 @@
+/*
+ * 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.fragment.cts;
+
+import static junit.framework.Assert.*;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class FragmentViewTests {
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setupInstrumentation() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    // Test that adding a fragment adds the Views in the proper order. Popping the back stack
+    // should remove the correct Views.
+    @Test
+    public void addFragments() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container, fragment1);
+
+        // Add another on top
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment2).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container, fragment1, fragment2);
+
+        // Now add two in one transaction:
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        final StrictViewFragment fragment4 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment3)
+                .add(R.id.fragmentContainer, fragment4)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container, fragment1, fragment2, fragment3, fragment4);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container, fragment1, fragment2);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(1, container.getChildCount());
+        assertChildren(container, fragment1);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container);
+    }
+
+    // Add fragments to multiple containers in the same transaction. Make sure that
+    // they pop correctly, too.
+    @Test
+    public void addTwoContainers() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+        ViewGroup container1 = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer1);
+        ViewGroup container2 = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer2);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer1, fragment1).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container1, fragment1);
+
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer2, fragment2).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container2, fragment2);
+
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        final StrictViewFragment fragment4 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment3)
+                .add(R.id.fragmentContainer2, fragment4)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container1, fragment1, fragment3);
+        assertChildren(container2, fragment2, fragment4);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container1, fragment1);
+        assertChildren(container2, fragment2);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container1, fragment1);
+        assertChildren(container2);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(0, container1.getChildCount());
+    }
+
+    // When you add a fragment that's has already been added, it should throw.
+    @Test
+    public void doubleAdd() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment1).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    fm.beginTransaction()
+                            .add(R.id.fragmentContainer, fragment1)
+                            .addToBackStack(null)
+                            .commit();
+                    fm.executePendingTransactions();
+                    fail("Adding a fragment that is already added should be an error");
+                } catch (IllegalStateException e) {
+                    // expected
+                }
+            }
+        });
+    }
+
+    // Make sure that removed fragments remove the right Views. Popping the back stack should
+    // add the Views back properly
+    @Test
+    public void removeFragments() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        final StrictViewFragment fragment4 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .add(R.id.fragmentContainer, fragment2, "2")
+                .add(R.id.fragmentContainer, fragment3, "3")
+                .add(R.id.fragmentContainer, fragment4, "4")
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container, fragment1, fragment2, fragment3, fragment4);
+
+        // Remove a view
+        fm.beginTransaction().remove(fragment4).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertEquals(3, container.getChildCount());
+        assertChildren(container, fragment1, fragment2, fragment3);
+
+        // remove another one
+        fm.beginTransaction().remove(fragment2).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container, fragment1, fragment3);
+
+        // Now remove the remaining:
+        fm.beginTransaction()
+                .remove(fragment3)
+                .remove(fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement1 = fm.findFragmentByTag("1");
+        final Fragment replacement3 = fm.findFragmentByTag("3");
+        assertChildren(container, replacement1, replacement3);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement2 = fm.findFragmentByTag("2");
+        assertChildren(container, replacement1, replacement3, replacement2);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement4 = fm.findFragmentByTag("4");
+        assertChildren(container, replacement1, replacement3, replacement2, replacement4);
+    }
+
+    // Removing a hidden fragment should remove the View and popping should bring it back hidden
+    @Test
+    public void removeHiddenView() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment1, "1").hide(fragment1).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container, fragment1);
+        assertTrue(fragment1.isHidden());
+
+        fm.beginTransaction().remove(fragment1).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement1 = fm.findFragmentByTag("1");
+        assertChildren(container, replacement1);
+        assertTrue(replacement1.isHidden());
+        assertEquals(View.GONE, replacement1.getView().getVisibility());
+        mInstrumentation.waitForIdleSync();
+    }
+
+    // Removing a detached fragment should do nothing to the View and popping should bring
+    // the Fragment back detached
+    @Test
+    public void removeDetatchedView() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .detach(fragment1)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container);
+        assertTrue(fragment1.isDetached());
+
+        fm.beginTransaction().remove(fragment1).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement1 = fm.findFragmentByTag("1");
+        assertChildren(container);
+        assertTrue(replacement1.isDetached());
+    }
+
+    // Unlike adding the same fragment twice, you should be able to add and then remove and then
+    // add the same fragment in one transaction.
+    @Test
+    public void addRemoveAdd() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment)
+                .remove(fragment)
+                .add(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container, fragment);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertChildren(container);
+    }
+
+    // Removing a fragment that isn't in should throw
+    @Test
+    public void removeNothThere() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction().remove(fragment).commit();
+        try {
+            FragmentTestUtil.executePendingTransactions(mActivityRule);
+            fail("Removing a fragment that isn't in should throw an exception");
+        } catch (Throwable t) {
+            // expected
+        }
+    }
+
+    // Hide a fragment and its View should be GONE. Then pop it and the View should be VISIBLE
+    @Test
+    public void hideFragment() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.beginTransaction().hide(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertTrue(fragment.isHidden());
+        assertEquals(View.GONE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertFalse(fragment.isHidden());
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+    }
+
+    // Hiding a hidden fragment should throw
+    @Test
+    public void doubleHide() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment)
+                .hide(fragment)
+                .hide(fragment)
+                .commit();
+        try {
+            FragmentTestUtil.executePendingTransactions(mActivityRule);
+            fail("Hiding a hidden fragment should throw an exception");
+        } catch (Throwable t) {
+            // expected
+        }
+    }
+
+    // Hiding a non-existing fragment should throw
+    @Test
+    public void hideUnAdded() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .hide(fragment)
+                .commit();
+        try {
+            FragmentTestUtil.executePendingTransactions(mActivityRule);
+            fail("Hiding a non-existing fragment should throw an exception");
+        } catch (Throwable t) {
+            // expected
+        }
+    }
+
+    // Show a hidden fragment and its View should be VISIBLE. Then pop it and the View should be
+    // BONE.
+    @Test
+    public void showFragment() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertTrue(fragment.isHidden());
+        assertEquals(View.GONE, fragment.getView().getVisibility());
+
+        fm.beginTransaction().show(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertFalse(fragment.isHidden());
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertTrue(fragment.isHidden());
+        assertEquals(View.GONE, fragment.getView().getVisibility());
+    }
+
+    // Showing a shown fragment should throw
+    @Test
+    public void showShown() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment)
+                .show(fragment)
+                .commit();
+        try {
+            FragmentTestUtil.executePendingTransactions(mActivityRule);
+            fail("Showing a visible fragment should throw an exception");
+        } catch (Throwable t) {
+            // expected
+        }
+    }
+
+    // Showing a non-existing fragment should throw
+    @Test
+    public void showUnAdded() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .show(fragment)
+                .commit();
+        try {
+            FragmentTestUtil.executePendingTransactions(mActivityRule);
+            fail("Showing a non-existing fragment should throw an exception");
+        } catch (Throwable t) {
+            // expected
+        }
+    }
+
+    // Detaching a fragment should remove the View from the hierarchy. Then popping it should
+    // bring it back VISIBLE
+    @Test
+    public void detachFragment() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertFalse(fragment.isDetached());
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.beginTransaction().detach(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container);
+        assertTrue(fragment.isDetached());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertFalse(fragment.isDetached());
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+    }
+
+    // Detaching a hidden fragment should remove the View from the hierarchy. Then popping it should
+    // bring it back hidden
+    @Test
+    public void detachHiddenFragment() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertFalse(fragment.isDetached());
+        assertTrue(fragment.isHidden());
+        assertEquals(View.GONE, fragment.getView().getVisibility());
+
+        fm.beginTransaction().detach(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container);
+        assertTrue(fragment.isHidden());
+        assertTrue(fragment.isDetached());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertTrue(fragment.isHidden());
+        assertFalse(fragment.isDetached());
+        assertEquals(View.GONE, fragment.getView().getVisibility());
+    }
+
+    // Detaching a detached fragment should throw
+    @Test
+    public void detachDetatched() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment)
+                .detach(fragment)
+                .detach(fragment)
+                .commit();
+        try {
+            FragmentTestUtil.executePendingTransactions(mActivityRule);
+            fail("Detaching a detached fragment should throw an exception");
+        } catch (Throwable t) {
+            // expected
+        }
+    }
+
+    // Detaching a non-existing fragment should throw
+    @Test
+    public void detachUnAdded() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .detach(fragment)
+                .commit();
+        try {
+            FragmentTestUtil.executePendingTransactions(mActivityRule);
+            fail("Detaching a non-existing fragment should throw an exception");
+        } catch (Throwable t) {
+            // expected
+        }
+    }
+
+    // Attaching a fragment should add the View back into the hierarchy. Then popping it should
+    // remove it again
+    @Test
+    public void attachFragment() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment).detach(fragment).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container);
+        assertTrue(fragment.isDetached());
+
+        fm.beginTransaction().attach(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertFalse(fragment.isDetached());
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container);
+        assertTrue(fragment.isDetached());
+    }
+
+    // Attaching a hidden fragment should add the View as GONE the hierarchy. Then popping it should
+    // remove it again.
+    @Test
+    public void attachHiddenFragment() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment)
+                .hide(fragment)
+                .detach(fragment)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container);
+        assertTrue(fragment.isDetached());
+        assertTrue(fragment.isHidden());
+
+        fm.beginTransaction().attach(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertTrue(fragment.isHidden());
+        assertFalse(fragment.isDetached());
+        assertEquals(View.GONE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container);
+        assertTrue(fragment.isDetached());
+        assertTrue(fragment.isHidden());
+    }
+
+    // Attaching an attached fragment should throw
+    @Test
+    public void attachAttached() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment)
+                .attach(fragment)
+                .commit();
+        try {
+            FragmentTestUtil.executePendingTransactions(mActivityRule);
+            fail("Attaching an attached fragment should throw an exception");
+        } catch (Throwable t) {
+            // expected
+        }
+    }
+
+    // Attaching a non-existing fragment should throw
+    @Test
+    public void attachUnAdded() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .attach(fragment)
+                .commit();
+        try {
+            FragmentTestUtil.executePendingTransactions(mActivityRule);
+            fail("Attaching a non-existing fragment should throw an exception");
+        } catch (Throwable t) {
+            // expected
+        }
+    }
+
+    // Simple replace of one fragment in a container. Popping should replace it back again
+    @Test
+    public void replaceOne() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment1, "1").commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment1);
+
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment2);
+        assertEquals(View.VISIBLE, fragment2.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        Fragment replacement1 = fm.findFragmentByTag("1");
+        assertNotNull(replacement1);
+        assertChildren(container, replacement1);
+        assertFalse(replacement1.isHidden());
+        assertTrue(replacement1.isAdded());
+        assertFalse(replacement1.isDetached());
+        assertEquals(View.VISIBLE, replacement1.getView().getVisibility());
+    }
+
+    // Replace of multiple fragments in a container. Popping should replace it back again
+    @Test
+    public void replaceTwo() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .add(R.id.fragmentContainer, fragment2, "2")
+                .hide(fragment2)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment1, fragment2);
+
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment3)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment3);
+        assertEquals(View.VISIBLE, fragment3.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        Fragment replacement1 = fm.findFragmentByTag("1");
+        Fragment replacement2 = fm.findFragmentByTag("2");
+        assertNotNull(replacement1);
+        assertNotNull(replacement2);
+        assertChildren(container, replacement1, replacement2);
+        assertFalse(replacement1.isHidden());
+        assertTrue(replacement1.isAdded());
+        assertFalse(replacement1.isDetached());
+        assertEquals(View.VISIBLE, replacement1.getView().getVisibility());
+
+        // fragment2 was hidden, so it should be returned hidden
+        assertTrue(replacement2.isHidden());
+        assertTrue(replacement2.isAdded());
+        assertFalse(replacement2.isDetached());
+        assertEquals(View.GONE, replacement2.getView().getVisibility());
+    }
+
+    // Replace of empty container. Should act as add and popping should just remove the fragment
+    @Test
+    public void replaceZero() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final StrictViewFragment fragment = new StrictViewFragment();
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container, fragment);
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container);
+    }
+
+    private void assertChildren(ViewGroup container, Fragment... fragments) {
+        final int numFragments = fragments == null ? 0 : fragments.length;
+        assertEquals("There aren't the correct number of fragment Views in its container",
+                numFragments, container.getChildCount());
+        for (int i = 0; i < numFragments; i++) {
+            assertEquals("Wrong Fragment View order for [" + i + "]", container.getChildAt(i),
+                    fragments[i].getView());
+        }
+    }
+}
diff --git a/tests/tests/accounts/AndroidManifest.xml b/tests/tests/accounts/AndroidManifest.xml
index d882690..0d4a534 100644
--- a/tests/tests/accounts/AndroidManifest.xml
+++ b/tests/tests/accounts/AndroidManifest.xml
@@ -36,6 +36,8 @@
         <activity android:name="android.accounts.cts.AccountRemovalDummyActivity" >
         </activity>
 
+        <activity android:name="android.accounts.cts.AccountAuthenticatorDummyActivity" />
+
         <service android:name="MockAccountService" android:exported="true"
                  android:process="android.accounts.cts">
             <intent-filter>
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java b/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java
index f8636a0..024ea3c 100644
--- a/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java
@@ -70,5 +70,7 @@
     public static final String KEY_RESULT = "test:result";
     public static final String KEY_TOKEN_EXPIRY = "test:token_duration";
 
+    public static final String KEY_ACCOUNT_SESSION_BUNDLE = "test:account_session_bundle";
+
     private Fixtures() {}
 }
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountAuthenticatorDummyActivity.java b/tests/tests/accounts/src/android/accounts/cts/AccountAuthenticatorDummyActivity.java
new file mode 100644
index 0000000..6c2d29e
--- /dev/null
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountAuthenticatorDummyActivity.java
@@ -0,0 +1,27 @@
+package android.accounts.cts;
+
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.cts.common.Fixtures;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Activity used by {@link android.accounts.cts.MockAccountAuthenticator} to test the
+ * behavior of {@link AccountManager} when authenticator returns intent.
+ */
+public class AccountAuthenticatorDummyActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Intent intent = getIntent();
+        AccountAuthenticatorResponse response = intent.getParcelableExtra(Fixtures.KEY_CALLBACK);
+        Intent result = intent.getParcelableExtra(Fixtures.KEY_RESULT);
+        if (response != null) {
+            response.onResult(result.getExtras());
+        }
+        setResult(RESULT_OK, result);
+        finish();
+    }
+}
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
index 3520d9c..930324f 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
@@ -24,6 +24,7 @@
 import android.accounts.AuthenticatorException;
 import android.accounts.OnAccountsUpdateListener;
 import android.accounts.OperationCanceledException;
+import android.accounts.cts.common.Fixtures;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
@@ -62,6 +63,8 @@
 
     public static final String ACCOUNT_PASSWORD = "android.accounts.cts.account.password";
 
+    public static final String ACCOUNT_STATUS_TOKEN = "android.accounts.cts.account.status.token";
+
     public static final String AUTH_TOKEN_TYPE = "mockAuthTokenType";
     public static final String AUTH_EXPIRING_TOKEN_TYPE = "mockAuthExpiringTokenType";
     public static final String AUTH_TOKEN_LABEL = "mockAuthTokenLabel";
@@ -98,6 +101,12 @@
     public static final Account CUSTOM_TOKEN_ACCOUNT =
             new Account(ACCOUNT_NAME,ACCOUNT_TYPE_CUSTOM);
 
+    public static final Bundle SESSION_BUNDLE = new Bundle();
+    public static final String SESSION_DATA_NAME_1 = "session.data.name.1";
+    public static final String SESSION_DATA_VALUE_1 = "session.data.value.1";
+
+    public static final String ERROR_MESSAGE = "android.accounts.cts.account.error.message";
+
     private static MockAccountAuthenticator mockAuthenticator;
     private static final int LATCH_TIMEOUT_MS = 500;
     private static AccountManager am;
@@ -127,6 +136,8 @@
 
         USERDATA_BUNDLE.putString(USERDATA_NAME_1, USERDATA_VALUE_1);
 
+        SESSION_BUNDLE.putString(SESSION_DATA_NAME_1, SESSION_DATA_VALUE_1);
+
         getMockAuthenticator(mContext);
 
         am = AccountManager.get(mContext);
@@ -2040,4 +2051,405 @@
         }
     }
 
+    /**
+     * Tests a basic startAddAccountSession() which returns a bundle containing
+     * encrypted session bundle, account password and status token.
+     */
+    public void testStartAddAccountSession()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+
+        Bundle resultBundle = startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options, null /* activity */, null /* callback */, null /* handler */);
+
+        validateStartAddAccountSessionParametersAndOptions(accountName, options);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startAddAccountSession() with null session bundle. Only account
+     * password and status token should be included in the result as session
+     * bundle is not inspected.
+     */
+    public void testStartAddAccountSessionWithNullSessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options, null /* activity */, null /* callback */, null /* handler */);
+
+        validateStartAddAccountSessionParametersAndOptions(accountName, options);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        assertNull(resultBundle.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+        assertEquals(ACCOUNT_PASSWORD, resultBundle.getString(AccountManager.KEY_PASSWORD));
+        assertEquals(ACCOUNT_STATUS_TOKEN,
+                resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    /**
+     * Tests startAddAccountSession() with empty session bundle. An encrypted
+     * session bundle, account password and status token should be included in
+     * the result as session bundle is not inspected.
+     */
+    public void testStartAddAccountSessionWithEmptySessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final Bundle options = new Bundle();
+        final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, new Bundle());
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options, null /* activity */, null /* callback */, null /* handler */);
+
+        validateStartAddAccountSessionParametersAndOptions(accountName, options);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startAddAccountSession with authenticator activity started. When
+     * Activity is provided, AccountManager would start the resolution Intent
+     * and return the final result which contains an encrypted session bundle,
+     * account password and status token.
+     */
+    public void testStartAddAccountSessionIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+
+        Bundle resultBundle = startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options, mActivity, null /* callback */, null /* handler */);
+
+        validateStartAddAccountSessionParametersAndOptions(accountName, options);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startAddAccountSession with KEY_INTENT returned but not started
+     * automatically. When no Activity is provided and authenticator requires
+     * additional data from user, KEY_INTENT will be returned by AccountManager.
+     */
+    public void testStartAddAccountSessionWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+
+        Bundle resultBundle = startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options, null /* activity */, null /* callback */, null /* handler */);
+
+        validateStartAddAccountSessionParametersAndOptions(accountName, options);
+
+        // Assert returned result
+        Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+        // Assert that KEY_INTENT is returned.
+        assertNotNull(returnIntent);
+        assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+        // Assert that no other data is returned.
+        assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+        assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+        assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    /**
+     * Tests startAddAccountSession error case. AuthenticatorException is
+     * expected when authenticator return
+     * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testStartAddAccountSessionError() throws IOException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_ERROR + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+
+        try {
+            startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE, REQUIRED_FEATURES,
+                options, null /* activity */, null /* callback */, null /* handler */);
+            fail("startAddAccountSession should throw AuthenticatorException in error case.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests startAddAccountSession() with callback and handler. An encrypted
+     * session bundle, account password and status token should be included in
+     * the result. Callback should be triggered with the result regardless of a
+     * handler is provider or not.
+     */
+    public void testStartAddAccountSessionWithCallbackAndHandler()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartAddAccountSessionWithCallbackAndHandler(null /* handler */);
+        testStartAddAccountSessionWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startAddAccountSession() with callback and handler and activity
+     * started. When Activity is provided, AccountManager would start the
+     * resolution Intent and return the final result which contains an encrypted
+     * session bundle, account password and status token. Callback should be
+     * triggered with the result regardless of a handler is provider or not.
+     */
+    public void testStartAddAccountSessionWithCallbackAndHandlerWithIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartAddAccountSessionWithCallbackAndHandlerWithIntervene(null /* handler */);
+        testStartAddAccountSessionWithCallbackAndHandlerWithIntervene(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startAddAccountSession() with callback and handler with KEY_INTENT
+     * returned. When no Activity is provided and authenticator requires
+     * additional data from user, KEY_INTENT will be returned by AccountManager
+     * in callback regardless of a handler is provider or not.
+     */
+    public void testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent(null /* handler */);
+        testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startAddAccountSession() error case with callback and handler.
+     * AuthenticatorException is expected when authenticator return
+     * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testStartAddAccountSessionErrorWithCallbackAndHandler()
+            throws IOException, OperationCanceledException {
+        testStartAddAccountSessionErrorWithCallbackAndHandler(null /* handler */);
+        testStartAddAccountSessionErrorWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+    }
+
+    private void testStartAddAccountSessionWithCallbackAndHandler(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+
+        // Wait with timeout for the callback to do its work
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = getResultExpectNoException(bundleFuture);
+
+                validateStartAddAccountSessionParametersAndOptions(accountName, options);
+
+                // Assert returned result
+                // Assert that auth token was stripped.
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+                validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE, REQUIRED_FEATURES, options,
+                mActivity, callback, handler);
+        waitForLatch(latch);
+    }
+
+    private void testStartAddAccountSessionWithCallbackAndHandlerWithIntervene(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+
+        // Wait with timeout for the callback to do its work
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = getResultExpectNoException(bundleFuture);
+
+                validateStartAddAccountSessionParametersAndOptions(accountName, options);
+
+                // Assert returned result
+                assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+                // Assert that auth token was stripped.
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+                validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE, REQUIRED_FEATURES, options,
+                mActivity, callback, handler);
+        waitForLatch(latch);
+    }
+
+    private void testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+
+        // Wait with timeout for the callback to do its work
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = getResultExpectNoException(bundleFuture);
+
+                validateStartAddAccountSessionParametersAndOptions(accountName, options);
+
+                // Assert returned result
+                Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+                // Assert KEY_INTENT is returned.
+                assertNotNull(returnIntent);
+                assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+                // Assert that no other data is returned.
+                assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+                assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+                assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+
+                latch.countDown();
+            }
+        };
+
+        startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE, REQUIRED_FEATURES, options, null,
+                callback, handler);
+        waitForLatch(latch);
+    }
+
+    private void testStartAddAccountSessionErrorWithCallbackAndHandler(Handler handler)
+            throws IOException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+
+        // Wait with timeout for the callback to do its work
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                try {
+                    bundleFuture.getResult();
+                    fail("should have thrown an AuthenticatorException");
+                } catch (OperationCanceledException e) {
+                    fail("should not throw an OperationCanceledException");
+                } catch (IOException e) {
+                    fail("should not throw an IOException");
+                } catch (AuthenticatorException e) {
+                    latch.countDown();
+                }
+            }
+        };
+
+        try {
+            startAddAccountSession(am, ACCOUNT_TYPE, AUTH_TOKEN_TYPE, REQUIRED_FEATURES, options,
+                    mActivity, callback, handler);
+            // AuthenticatorException should be thrown when authenticator
+            // returns AccountManager.ERROR_CODE_INVALID_RESPONSE.
+            fail("should have thrown an AuthenticatorException");
+        } catch (AuthenticatorException e1) {
+        }
+
+        waitForLatch(latch);
+    }
+
+    private Bundle startAddAccountSession(AccountManager am, String accountType,
+            String authTokenType,
+            String[] requiredFeatures, Bundle options, Activity activity,
+            AccountManagerCallback<Bundle> callback, Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+
+        AccountManagerFuture<Bundle> futureBundle = am.startAddAccountSession(accountType,
+                authTokenType,
+                requiredFeatures, options, activity, callback, handler);
+
+        Bundle resultBundle = futureBundle.getResult();
+        assertTrue(futureBundle.isDone());
+        assertNotNull(resultBundle);
+
+        return resultBundle;
+    }
+
+    private Bundle createOptionsWithAccountName(final String accountName) {
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, SESSION_BUNDLE);
+        options.putAll(OPTIONS_BUNDLE);
+        return options;
+    }
+
+    private void validateStartAddAccountSessionParametersAndOptions(
+            String accountName, Bundle options) {
+        // Assert parameters has been passed correctly
+        validateAccountAndAuthTokenType();
+        validateFeatures();
+
+        // Validate options
+        validateOptions(options, mockAuthenticator.mOptionsStartAddAccountSession);
+        assertNotNull(mockAuthenticator.mOptionsStartAddAccountSession);
+        assertEquals(accountName, mockAuthenticator.mOptionsStartAddAccountSession
+                .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateSystemOptions(mockAuthenticator.mOptionsStartAddAccountSession);
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+    }
+
+    private void validateSessionBundleAndPasswordAndStatusTokenResult(Bundle resultBundle) {
+        Bundle sessionBundle = resultBundle.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(sessionBundle);
+        // Assert that session bundle is encrypted and hence data not visible.
+        assertNull(sessionBundle.getString(SESSION_DATA_NAME_1));
+        assertEquals(ACCOUNT_PASSWORD, resultBundle.getString(AccountManager.KEY_PASSWORD));
+        assertEquals(ACCOUNT_STATUS_TOKEN,
+                resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    private Bundle getResultExpectNoException(AccountManagerFuture<Bundle> bundleFuture) {
+        try {
+            return bundleFuture.getResult();
+        } catch (OperationCanceledException e) {
+            fail("should not throw an OperationCanceledException");
+        } catch (IOException e) {
+            fail("should not throw an IOException");
+        } catch (AuthenticatorException e) {
+            fail("should not throw an AuthenticatorException");
+        }
+        return null;
+    }
 }
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
index 2068f4c..b3f7a82 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
@@ -25,6 +25,7 @@
 import android.accounts.cts.common.Fixtures;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.test.AndroidTestCase;
 
@@ -222,5 +223,41 @@
                 getContext().getPackageName());
         assertEquals(0, accounts.length);
     }
+
+    /**
+     * Tests startAddAccountSession default implementation. An encrypted session
+     * bundle should always be returned without password or status token.
+     */
+    public void testStartAddAccountSessionDefaultImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+        AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession(
+                Fixtures.TYPE_STANDARD_UNAFFILIATED, null /* authTokenType */,
+                null /* requiredFeatures */, options, null /* activity */, null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+
+        // Validate that auth token was stripped from result.
+        assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+
+        // Validate that no password nor status token is returned in the result
+        // for default implementation.
+        validateNullPasswordAndStatusToken(result);
+
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        // Validate session bundle is returned but data in the bundle is
+        // encrypted and hence not visible.
+        assertNotNull(sessionBundle);
+        assertNull(sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE));
+    }
+
+    private void validateNullPasswordAndStatusToken(Bundle result) {
+        assertNull(result.getString(AccountManager.KEY_PASSWORD));
+        assertNull(result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
 }
 
diff --git a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
index 470b629..95d6ed6 100644
--- a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
+++ b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
@@ -21,6 +21,7 @@
 import android.accounts.AccountAuthenticatorResponse;
 import android.accounts.AccountManager;
 import android.accounts.NetworkErrorException;
+import android.accounts.cts.common.Fixtures;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
@@ -56,6 +57,7 @@
     public Bundle mOptionsConfirmCredentials;
     public Bundle mOptionsAddAccount;
     public Bundle mOptionsGetAuthToken;
+    public Bundle mOptionsStartAddAccountSession;
     Account mAccount;
     String[] mFeatures;
 
@@ -116,6 +118,7 @@
         mOptionsAddAccount = null;
         mOptionsGetAuthToken = null;
         mOptionsConfirmCredentials = null;
+        mOptionsStartAddAccountSession = null;
         mAccount = null;
         mFeatures = null;
     }
@@ -312,4 +315,75 @@
         return super.getAccountCredentialsForCloning(response, account);
     }
 
+
+    /**
+     * Start add account flow of the specified accountType to authenticate user.
+     */
+    @Override
+    public Bundle startAddAccountSession(AccountAuthenticatorResponse response, String accountType,
+            String authTokenType, String[] requiredFeatures, Bundle options)
+            throws NetworkErrorException {
+
+        this.mResponse = response;
+        this.mAccountType = accountType;
+        this.mAuthTokenType = authTokenType;
+        this.mRequiredFeatures = requiredFeatures;
+        this.mOptionsStartAddAccountSession = options;
+
+        String accountName = null;
+        boolean isCallbackRequired = false;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+            isCallbackRequired = options.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+            sessionBundle = options.getBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+            result.putString(AccountManager.KEY_PASSWORD, AccountManagerTest.ACCOUNT_PASSWORD);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+            eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD,
+                    AccountManagerTest.ACCOUNT_PASSWORD);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+                    sessionBundle);
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+            intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+            String errorMsg = "Default Error Message";
+            if (options != null) {
+                errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+                errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+            }
+            result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+            result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        try {
+            return (isCallbackRequired) ? null : result;
+        } finally {
+            if (isCallbackRequired) {
+                response.onResult(result);
+            }
+        }
+    }
+
 }
diff --git a/tests/tests/animation/Android.mk b/tests/tests/animation/Android.mk
index 205adda..ed42d74 100644
--- a/tests/tests/animation/Android.mk
+++ b/tests/tests/animation/Android.mk
@@ -24,13 +24,19 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES += \
+    android-support-test \
+    mockito-target \
+    android-common \
+    ctsdeviceutil \
+    ctstestrunner \
+    platform-test-annotations
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-LOCAL_SDK_VERSION := current
-
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/animation/src/android/animation/cts/AnimatorListenerAdapterTest.java b/tests/tests/animation/src/android/animation/cts/AnimatorListenerAdapterTest.java
new file mode 100644
index 0000000..c6c0bc4
--- /dev/null
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorListenerAdapterTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.animation.cts;
+
+import android.animation.AnimatorListenerAdapter;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+@SmallTest
+public class AnimatorListenerAdapterTest {
+    /**
+     * AnimatorListenerAdapter has a noop implementation of the AnimatorListener interface.
+     * It should do nothing, including when nulls are passed to it.
+     * <p>
+     * Mostly this test pokes the implementation so that it is counted as tested. There isn't
+     * much to test here since it has no implementation.
+     */
+    @Test
+    public void testNullOk() throws Throwable {
+        AnimatorListenerAdapter adapter = new MyAdapter();
+        adapter.onAnimationStart(null);
+        adapter.onAnimationEnd(null);
+        adapter.onAnimationRepeat(null);
+        adapter.onAnimationCancel(null);
+        adapter.onAnimationPause(null);
+        adapter.onAnimationResume(null);
+    }
+
+    private static class MyAdapter extends AnimatorListenerAdapter {
+    }
+}
diff --git a/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java b/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
index 3bf86de..77b1583 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
@@ -438,6 +438,82 @@
         assertSame(animator2.getInterpolator(), clone2.getInterpolator());
     }
 
+    public void testSetSynchronized() throws Throwable {
+        final TargetObj obj1 = new TargetObj();
+        final TargetObj obj2 = new TargetObj();
+        ObjectAnimator anim1 = ObjectAnimator.ofFloat(obj1, "val", 0, 1);
+        ObjectAnimator anim2 = ObjectAnimator.ofFloat(obj1, "val", 0, 1);
+        ObjectAnimator anim3 = ObjectAnimator.ofFloat(obj1, "val", 0, 1);
+        anim1.setStartDelay(100);
+        anim2.setStartDelay(400);
+        anim3.setStartDelay(700);
+        final AnimatorSet combined1 = new AnimatorSet();
+        combined1.playTogether(anim1, anim2, anim3);
+
+        ObjectAnimator anim4 = ObjectAnimator.ofFloat(obj2, "val", 0, 1);
+        ObjectAnimator anim5 = ObjectAnimator.ofFloat(obj2, "val", 0, 1);
+        ObjectAnimator anim6 = ObjectAnimator.ofFloat(obj2, "val", 0, 1);
+        final AnimatorSet combined2 = new AnimatorSet();
+        combined2.playSequentially(anim4, anim5, anim6);
+        combined2.setStartDelay(100);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                combined1.start();
+                combined2.start();
+            }
+        });
+
+        while (combined1.isRunning()) {
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    assertEquals(obj1.value, obj2.value);
+                }
+            });
+        }
+    }
+
+    public void testNotifiesAfterEnd() throws Throwable {
+        final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
+        Animator.AnimatorListener listener = new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                assertTrue(animation.isStarted());
+                assertTrue(animation.isRunning());
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                assertFalse(animation.isRunning());
+                assertFalse(animation.isStarted());
+                super.onAnimationEnd(animation);
+            }
+        };
+        animator.addListener(listener);
+        final AnimatorSet animatorSet = new AnimatorSet();
+        animatorSet.playTogether(animator);
+        animatorSet.addListener(listener);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                animatorSet.start();
+                animator.end();
+                assertFalse(animator.isStarted());
+                assertFalse(animatorSet.isStarted());
+            }
+        });
+    }
+
+    static class TargetObj {
+        public float value = 0;
+
+        public void setVal(float value) {
+            this.value = value;
+        }
+    }
+
     class AnimateObject {
         int x = 1;
         int y = 2;
diff --git a/tests/tests/animation/src/android/animation/cts/EvaluatorTest.java b/tests/tests/animation/src/android/animation/cts/EvaluatorTest.java
index 0812351..9c90f40 100644
--- a/tests/tests/animation/src/android/animation/cts/EvaluatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/EvaluatorTest.java
@@ -27,10 +27,12 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 
 /**
  * Tests for the various Evaluator classes in android.animation
  */
+@SmallTest
 public class EvaluatorTest extends InstrumentationTestCase {
 
     public void testFloatEvaluator() {
@@ -50,10 +52,18 @@
     }
 
     public void testFloatArrayEvaluator() {
+        FloatArrayEvaluator evaluator = new FloatArrayEvaluator();
+        floatArrayEvaluatorTestImpl(evaluator, null);
+
+        float[] reusableArray = new float[2];
+        FloatArrayEvaluator evaluator2 = new FloatArrayEvaluator(reusableArray);
+        floatArrayEvaluatorTestImpl(evaluator2, reusableArray);
+    }
+
+    private void floatArrayEvaluatorTestImpl(FloatArrayEvaluator evaluator, float[] reusedArray) {
         float[] start = {0f, 0f};
         float[] end = {.8f, 1.0f};
         float fraction = 0.5f;
-        FloatArrayEvaluator evaluator = new FloatArrayEvaluator();
 
         float[] result = evaluator.evaluate(0, start, end);
         assertEquals(start[0], result[0], .001f);
@@ -66,51 +76,63 @@
         result = evaluator.evaluate(1, start, end);
         assertEquals(end[0], result[0], .001f);
         assertEquals(end[1], result[1], .001f);
+
+        if (reusedArray != null) {
+            assertEquals(reusedArray, result);
+        }
     }
 
     public void testArgbEvaluator() throws Throwable {
-        final int RED =  0xffFF8080;
-        final int BLUE = 0xff8080FF;
-        int aRED = Color.alpha(RED);
-        int rRED = Color.red(RED);
-        int gRED = Color.green(RED);
-        int bRED = Color.blue(RED);
-        int aBLUE = Color.alpha(BLUE);
-        int rBLUE = Color.red(BLUE);
-        int gBLUE = Color.green(BLUE);
-        int bBLUE = Color.blue(BLUE);
+        final int START =  0xffFF8080;
+        final int END = 0xff8080FF;
+        int aSTART = Color.alpha(START);
+        int rSTART = Color.red(START);
+        int gSTART = Color.green(START);
+        int bSTART = Color.blue(START);
+        int aEND = Color.alpha(END);
+        int rEND = Color.red(END);
+        int gEND = Color.green(END);
+        int bEND = Color.blue(END);
 
         final ArgbEvaluator evaluator = new ArgbEvaluator();
 
-        int result = (Integer) evaluator.evaluate(0, RED, BLUE);
+        int result = (Integer) evaluator.evaluate(0, START, END);
         int aResult = Color.alpha(result);
         int rResult = Color.red(result);
         int gResult = Color.green(result);
         int bResult = Color.blue(result);
-        assertEquals(aRED, aResult);
-        assertEquals(rRED, rResult);
-        assertEquals(gRED, gResult);
-        assertEquals(bRED, bResult);
+        assertEquals(aSTART, aResult);
+        assertEquals(rSTART, rResult);
+        assertEquals(gSTART, gResult);
+        assertEquals(bSTART, bResult);
 
-        result = (Integer) evaluator.evaluate(.5f, RED, BLUE);
+        result = (Integer) evaluator.evaluate(.5f, START, END);
         aResult = Color.alpha(result);
         rResult = Color.red(result);
         gResult = Color.green(result);
         bResult = Color.blue(result);
         assertEquals(0xff, aResult);
-        assertEquals(rRED + (int)(.5f * (rBLUE - rRED)), rResult);
-        assertEquals(gRED + (int)(.5f * (gBLUE - gRED)), gResult);
-        assertEquals(bRED + (int)(.5f * (bBLUE - bRED)), bResult);
+        assertEquals(0x80, gResult);
+        if (rSTART < rEND) {
+            assertTrue(rResult > rSTART && rResult < rEND);
+        } else {
+            assertTrue(rResult < rSTART && rResult > rEND);
+        }
+        if (bSTART < bEND) {
+            assertTrue(bResult > bSTART && bResult < bEND);
+        } else {
+            assertTrue(bResult < bSTART && bResult > bEND);
+        }
 
-        result = (Integer) evaluator.evaluate(1, RED, BLUE);
+        result = (Integer) evaluator.evaluate(1, START, END);
         aResult = Color.alpha(result);
         rResult = Color.red(result);
         gResult = Color.green(result);
         bResult = Color.blue(result);
-        assertEquals(aBLUE, aResult);
-        assertEquals(rBLUE, rResult);
-        assertEquals(gBLUE, gResult);
-        assertEquals(bBLUE, bResult);
+        assertEquals(aEND, aResult);
+        assertEquals(rEND, rResult);
+        assertEquals(gEND, gResult);
+        assertEquals(bEND, bResult);
     }
 
     public void testIntEvaluator() throws Throwable {
@@ -130,10 +152,18 @@
     }
 
     public void testIntArrayEvaluator() {
+        IntArrayEvaluator evaluator = new IntArrayEvaluator();
+        intArrayEvaluatorTestImpl(evaluator, null);
+
+        int[] reusableArray = new int[2];
+        IntArrayEvaluator evaluator2 = new IntArrayEvaluator(reusableArray);
+        intArrayEvaluatorTestImpl(evaluator2, reusableArray);
+    }
+
+    private void intArrayEvaluatorTestImpl(IntArrayEvaluator evaluator, int[] reusedArray) {
         int[] start = {0, 0};
         int[] end = {80, 100};
         float fraction = 0.5f;
-        IntArrayEvaluator evaluator = new IntArrayEvaluator();
 
         int[] result = evaluator.evaluate(0, start, end);
         assertEquals(start[0], result[0]);
@@ -146,10 +176,22 @@
         result = evaluator.evaluate(1, start, end);
         assertEquals(end[0], result[0]);
         assertEquals(end[1], result[1]);
+
+        if (reusedArray != null) {
+            assertEquals(reusedArray, result);
+        }
     }
 
     public void testRectEvaluator() throws Throwable {
         final RectEvaluator evaluator = new RectEvaluator();
+        rectEvaluatorTestImpl(evaluator, null);
+
+        Rect reusableRect = new Rect();
+        final RectEvaluator evaluator2 = new RectEvaluator(reusableRect);
+        rectEvaluatorTestImpl(evaluator2, reusableRect);
+    }
+
+    private void rectEvaluatorTestImpl(RectEvaluator evaluator, Rect reusedRect) {
         final Rect start = new Rect(0, 0, 0, 0);
         final Rect end = new Rect(100, 200, 300, 400);
         final float fraction = 0.5f;
@@ -171,10 +213,22 @@
         assertEquals(end.top, result.top, .001f);
         assertEquals(end.right, result.right, .001f);
         assertEquals(end.bottom, result.bottom, .001f);
+
+        if (reusedRect != null) {
+            assertEquals(reusedRect, result);
+        }
     }
 
     public void testPointFEvaluator() throws Throwable {
         final PointFEvaluator evaluator = new PointFEvaluator();
+        pointFEvaluatorTestImpl(evaluator, null);
+
+        PointF reusablePoint = new PointF();
+        final PointFEvaluator evaluator2 = new PointFEvaluator(reusablePoint);
+        pointFEvaluatorTestImpl(evaluator2, reusablePoint);
+    }
+
+    private void pointFEvaluatorTestImpl(PointFEvaluator evaluator, PointF reusedPoint) {
         final PointF start = new PointF(0, 0);
         final PointF end = new PointF(100, 200);
         final float fraction = 0.5f;
@@ -190,6 +244,10 @@
         result = evaluator.evaluate(1, start, end);
         assertEquals(end.x, result.x, .001f);
         assertEquals(end.y, result.y, .001f);
+
+        if (reusedPoint != null) {
+            assertEquals(reusedPoint, result);
+        }
     }
 
     /**
diff --git a/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
index 6ff1cf9..a96b8c9 100644
--- a/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
@@ -16,17 +16,39 @@
 
 package android.animation.cts;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.animation.TypeConverter;
 import android.animation.ValueAnimator;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.PointF;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Property;
+import android.view.View;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Interpolator;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 public class ObjectAnimatorTest extends
         ActivityInstrumentationTestCase2<AnimationActivity> {
+    private static final float LINE1_START = -32f;
+    private static final float LINE1_END = -2f;
+    private static final float LINE1_Y = 0f;
+    private static final float LINE2_START = 2f;
+    private static final float LINE2_END = 12f;
+    private static final float QUADRATIC_CTRL_PT1_X = 0f;
+    private static final float QUADRATIC_CTRL_PT1_Y = 0f;
+    private static final float QUADRATIC_CTRL_PT2_X = 50f;
+    private static final float QUADRATIC_CTRL_PT2_Y = 20f;
+    private static final float QUADRATIC_CTRL_PT3_X = 100f;
+    private static final float QUADRATIC_CTRL_PT3_Y = 0f;
+
     private AnimationActivity mActivity;
     private ObjectAnimator mObjectAnimator;
     private long mDuration = 1000;
@@ -162,6 +184,59 @@
         assertTrue(endColor <= i.intValue());
     }
 
+    public void testOfArgb() throws Throwable {
+        Object object = mActivity.view;
+        String property = "backgroundColor";
+        int start = 0xffff0000;
+        int end = 0xff0000ff;
+        int[] values = {start, end};
+        int startRed = Color.red(start);
+        int startBlue = Color.blue(start);
+        int endRed = Color.red(end);
+        int endBlue = Color.blue(end);
+        final ObjectAnimator animator = ObjectAnimator.ofArgb(object, property, start, end);
+        animator.setDuration(mDuration);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                if (animation.getAnimatedFraction() > .05f) {
+                    latch.countDown();
+                }
+            }
+        });
+
+        this.runTestOnUiThread(new Runnable(){
+            public void run() {
+                animator.start();
+            }
+        });
+        boolean isRunning = animator.isRunning();
+        assertTrue(isRunning);
+
+        assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
+
+        Integer animatedValue = (Integer) animator.getAnimatedValue();
+        int alpha = Color.alpha(animatedValue);
+        int red = Color.red(animatedValue);
+        int green = Color.green(animatedValue);
+        int blue = Color.blue(animatedValue);
+        assertTrue(red < startRed);
+        assertTrue(red > endRed);
+        assertTrue(blue > startBlue);
+        assertTrue(blue < endBlue);
+        assertEquals(255, alpha);
+        assertEquals(0, green);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                animator.cancel();
+            }
+        });
+    }
+
     public void testGetPropertyName() throws Throwable {
         Object object = mActivity.view.newBall;
         String propertyName = "backgroundColor";
@@ -230,6 +305,473 @@
         assertEquals(interpolator, cloneAnimator.getInterpolator());
     }
 
+    public void testOfFloat_Path() throws Throwable {
+        // Test for ObjectAnimator.ofFloat(Object, String, String, Path)
+        // Create a path that contains two disconnected line segments. Check that the animated
+        // property x and property y always stay on the line segments.
+        Path path = new Path();
+        path.moveTo(LINE1_START, LINE1_Y);
+        path.lineTo(LINE1_END, LINE1_Y);
+        path.moveTo(LINE2_START, LINE2_START);
+        path.lineTo(LINE2_END, LINE2_END);
+        final double totalLength = (LINE1_END - LINE1_START) + Math.sqrt(
+                (LINE2_END - LINE2_START) * (LINE2_END - LINE2_START) +
+                (LINE2_END - LINE2_START) * (LINE2_END - LINE2_START));
+        final double firstSegEndFraction = (LINE1_END - LINE1_START) / totalLength;
+        final float delta = 0.01f;
+
+        Object target = new Object() {
+            public void setX(float x) {
+            }
+
+            public void setY(float y) {
+            }
+        };
+        final CountDownLatch endLatch = new CountDownLatch(1);
+
+        final ObjectAnimator anim = ObjectAnimator.ofFloat(target, "x", "y", path);
+        anim.setDuration(200);
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float fraction = animation.getAnimatedFraction();
+                float x = (Float) animation.getAnimatedValue("x");
+                float y = (Float) animation.getAnimatedValue("y");
+
+                // Check that the point is on the path.
+                if (x <= 0) {
+                    // First line segment is a horizontal line.
+                    assertTrue(x >= LINE1_START);
+                    assertTrue(x <= LINE1_END);
+                    assertEquals(LINE1_Y, y);
+
+                    // Check that the time animation stays on the first segment is proportional to
+                    // the length of the first line segment.
+                    assertTrue(fraction < firstSegEndFraction + delta);
+                } else {
+                    assertTrue(x >= LINE2_START);
+                    assertTrue(x <= LINE2_END);
+                    assertEquals(x, y);
+
+                    // Check that the time animation stays on the second segment is proportional to
+                    // the length of the second line segment.
+                    assertTrue(fraction > firstSegEndFraction - delta);
+                }
+            }
+        });
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(400, TimeUnit.MILLISECONDS));
+    }
+
+    public void testOfInt_Path() throws Throwable {
+        // Test for ObjectAnimator.ofInt(Object, String, String, Path)
+        // Create a path that contains two disconnected line segments. Check that the animated
+        // property x and property y always stay on the line segments.
+        Path path = new Path();
+        path.moveTo(LINE1_START, -LINE1_START);
+        path.lineTo(LINE1_END, -LINE1_END);
+        path.moveTo(LINE2_START, LINE2_START);
+        path.lineTo(LINE2_END, LINE2_END);
+
+        Object target = new Object() {
+            public void setX(float x) {
+            }
+
+            public void setY(float y) {
+            }
+        };
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final ObjectAnimator anim = ObjectAnimator.ofInt(target, "x", "y", path);
+        anim.setDuration(200);
+
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float fraction = animation.getAnimatedFraction();
+                int x = (Integer) animation.getAnimatedValue("x");
+                int y = (Integer) animation.getAnimatedValue("y");
+
+                // Check that the point is on the path.
+                if (x <= 0) {
+                    // Check that the time animation stays on the first segment is proportional to
+                    // the length of the first line segment.
+                    assertTrue(x >= LINE1_START);
+                    assertTrue(x <= LINE1_END);
+                    assertEquals(x, -y);
+
+                    // First line segment is 3 times as long as the second line segment, so the
+                    // 3/4 of the animation duration will be spent on the first line segment.
+                    assertTrue(fraction <= 0.75f);
+                } else {
+                    // Check that the time animation stays on the second segment is proportional to
+                    // the length of the second line segment.
+                    assertTrue(x >= LINE2_START);
+                    assertTrue(x <= LINE2_END);
+                    assertEquals(x, y);
+
+                    assertTrue(fraction >= 0.75f);
+                }
+            }
+        });
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(400, TimeUnit.MILLISECONDS));
+
+    }
+
+    public void testOfMultiFloat_Path() throws Throwable {
+        // Test for ObjectAnimator.ofMultiFloat(Object, String, Path);
+        // Create a quadratic bezier curve that are symmetric about the vertical line (x = 50).
+        // Expect when fraction < 0.5, x < 50, otherwise, x >= 50.
+        Path path = new Path();
+        path.moveTo(QUADRATIC_CTRL_PT1_X, QUADRATIC_CTRL_PT1_Y);
+        path.quadTo(QUADRATIC_CTRL_PT2_X, QUADRATIC_CTRL_PT2_Y,
+                QUADRATIC_CTRL_PT3_X, QUADRATIC_CTRL_PT3_Y);
+
+        Object target = new Object() {
+            public void setPosition(float x, float y) {
+            }
+        };
+
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final ObjectAnimator anim = ObjectAnimator.ofMultiFloat(target, "position", path);
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.setDuration(200);
+
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            float lastFraction = 0;
+            float lastX = 0;
+            float lastY = 0;
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float[] values = (float[]) animation.getAnimatedValue();
+                assertEquals(2, values.length);
+                float x = values[0];
+                float y = values[1];
+                float fraction = animation.getAnimatedFraction();
+                // Given that the curve is symmetric about the line (x = 50), x should be less than
+                // 50 for half of the animation duration.
+                if (fraction < 0.5) {
+                    assertTrue(x < QUADRATIC_CTRL_PT2_X);
+                } else {
+                    assertTrue(x >= QUADRATIC_CTRL_PT2_X);
+                }
+
+                if (lastFraction > 0.5) {
+                    // x should be increasing, y should be decreasing
+                    assertTrue(x >= lastX);
+                    assertTrue(y <= lastY);
+                } else if (fraction <= 0.5) {
+                    // when fraction <= 0.5, both x, y should be increasing
+                    assertTrue(x >= lastX);
+                    assertTrue(y >= lastY);
+                }
+                lastX = x;
+                lastY = y;
+                lastFraction = fraction;
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(400, TimeUnit.MILLISECONDS));
+    }
+
+    public void testOfMultiFloat() throws Throwable {
+        // Test for ObjectAnimator.ofMultiFloat(Object, String, float[][]);
+        final float[][] data = new float[10][];
+        for (int i = 0; i < data.length; i++) {
+            data[i] = new float[3];
+            data[i][0] = i;
+            data[i][1] = i * 2;
+            data[i][2] = 0f;
+        }
+
+        Object target = new Object() {
+            public void setPosition(float x, float y, float z) {
+            }
+        };
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final ObjectAnimator anim = ObjectAnimator.ofMultiFloat(target, "position", data);
+        anim.setInterpolator(null);
+        anim.setDuration(60);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float fraction = animation.getAnimatedFraction();
+                float[] values = (float[]) animation.getAnimatedValue();
+                assertEquals(3, values.length);
+
+                float expectedX = fraction * (data.length - 1);
+
+                assertEquals(expectedX, values[0]);
+                assertEquals(expectedX * 2, values[1]);
+                assertEquals(0f, values[2]);
+            }
+        });
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    public void testOfMultiInt_Path() throws Throwable {
+        // Test for ObjectAnimator.ofMultiInt(Object, String, Path);
+        // Create a quadratic bezier curve that are symmetric about the vertical line (x = 50).
+        // Expect when fraction < 0.5, x < 50, otherwise, x >= 50.
+        Path path = new Path();
+        path.moveTo(QUADRATIC_CTRL_PT1_X, QUADRATIC_CTRL_PT1_Y);
+        path.quadTo(QUADRATIC_CTRL_PT2_X, QUADRATIC_CTRL_PT2_Y,
+                QUADRATIC_CTRL_PT3_X, QUADRATIC_CTRL_PT3_Y);
+
+        Object target = new Object() {
+            public void setPosition(int x, int y) {
+            }
+        };
+
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final ObjectAnimator anim = ObjectAnimator.ofMultiInt(target, "position", path);
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.setDuration(200);
+
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            float lastFraction = 0;
+            int lastX = 0;
+            int lastY = 0;
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                int[] values = (int[]) animation.getAnimatedValue();
+                assertEquals(2, values.length);
+                int x = values[0];
+                int y = values[1];
+                float fraction = animation.getAnimatedFraction();
+                // Given that the curve is symmetric about the line (x = 50), x should be less than
+                // 50 for half of the animation duration.
+                if (fraction < 0.5) {
+                    assertTrue(x < QUADRATIC_CTRL_PT2_X);
+                } else {
+                    assertTrue(x >= QUADRATIC_CTRL_PT2_X);
+                }
+
+                if (lastFraction > 0.5) {
+                    // x should be increasing, y should be decreasing
+                    assertTrue(x >= lastX);
+                    assertTrue(y <= lastY);
+                } else if (fraction <= 0.5) {
+                    // when fraction <= 0.5, both x, y should be increasing
+                    assertTrue(x >= lastX);
+                    assertTrue(y >= lastY);
+                }
+                lastX = x;
+                lastY = y;
+                lastFraction = fraction;
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(400, TimeUnit.MILLISECONDS));
+    }
+
+    public void testOfMultiInt() throws Throwable {
+        // Test for ObjectAnimator.ofMultiFloat(Object, String, int[][]);
+        final int[][] data = new int[10][];
+        for (int i = 0; i < data.length; i++) {
+            data[i] = new int[3];
+            data[i][0] = i;
+            data[i][1] = i * 2;
+            data[i][2] = 0;
+        }
+
+        Object target = new Object() {
+            public void setPosition(int x, int y, int z) {
+            }
+        };
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final ObjectAnimator anim = ObjectAnimator.ofMultiInt(target, "position", data);
+        anim.setInterpolator(null);
+        anim.setDuration(60);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float fraction = animation.getAnimatedFraction();
+                int[] values = (int[]) animation.getAnimatedValue();
+                assertEquals(3, values.length);
+
+                int expectedX = Math.round(fraction * (data.length - 1));
+                int expectedY = Math.round(fraction * (data.length - 1) * 2);
+
+                // Allow a delta of 1 for rounding errors.
+                assertEquals(expectedX, values[0], 1);
+                assertEquals(expectedY, values[1], 1);
+                assertEquals(0, values[2]);
+            }
+        });
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    public void testOfObject_Converter() throws Throwable {
+        // Test for ObjectAnimator.ofObject(Object, String, TypeConverter<T, V>, Path)
+        // Create a path that contains two disconnected line segments. Check that the animated
+        // property x and property y always stay on the line segments.
+        Path path = new Path();
+        path.moveTo(LINE1_START, -LINE1_START);
+        path.lineTo(LINE1_END, -LINE1_END);
+        path.moveTo(LINE2_START, LINE2_START);
+        path.lineTo(LINE2_END, LINE2_END);
+
+        Object target1 = new Object() {
+            public void setDistance(float distance) {
+            }
+        };
+        Object target2 = new Object() {
+            public void setPosition(PointF pos) {
+            }
+        };
+        TypeConverter<PointF, Float> converter = new TypeConverter<PointF, Float>(
+                PointF.class, Float.class) {
+            @Override
+            public Float convert(PointF value) {
+                return (float) Math.sqrt(value.x * value.x + value.y * value.y);
+            }
+        };
+        final CountDownLatch endLatch = new CountDownLatch(2);
+
+        // Create two animators. One use a converter that converts the point to distance to origin.
+        // The other one does not have a type converter.
+        final ObjectAnimator anim1 = ObjectAnimator.ofObject(target1, "distance", converter, path);
+        anim1.setDuration(100);
+        anim1.setInterpolator(null);
+        anim1.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        final ObjectAnimator anim2 = ObjectAnimator.ofObject(target2, "position", null, path);
+        anim2.setDuration(100);
+        anim2.setInterpolator(null);
+        anim2.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+        anim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            // Set the initial value of the distance to the distance between the first point on
+            // the path to the origin.
+            float mLastDistance = (float) (32 * Math.sqrt(2));
+            float mLastFraction = 0f;
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float fraction = anim1.getAnimatedFraction();
+                assertEquals(fraction, anim2.getAnimatedFraction());
+                float distance = (Float) anim1.getAnimatedValue();
+                PointF position = (PointF) anim2.getAnimatedValue();
+
+                // Manually calculate the distance for the animator that doesn't have a
+                // TypeConverter, and expect the result to be the same as the animation value from
+                // the type converter.
+                float distanceFromPosition = (float) Math.sqrt(
+                        position.x * position.x + position.y * position.y);
+                assertEquals(distance, distanceFromPosition, 0.0001f);
+
+                if (mLastFraction > 0.75) {
+                    // In the 2nd line segment of the path, distance to origin should be increasing.
+                    assertTrue(distance >= mLastDistance);
+                } else if (fraction < 0.75) {
+                    assertTrue(distance <= mLastDistance);
+                }
+                mLastDistance = distance;
+                mLastFraction = fraction;
+            }
+        });
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim1.start();
+                anim2.start();
+            }
+        });
+
+        // Wait until both of the animations finish
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
     public void testIsStarted() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "y";
@@ -308,6 +850,46 @@
         });
     }
 
+    public void testCachedValues() throws Throwable {
+        final AnimTarget target = new AnimTarget();
+        final ObjectAnimator anim = ObjectAnimator.ofFloat(target, "testValue", 100);
+        anim.setDuration(200);
+        final CountDownLatch twoFramesLatch = new CountDownLatch(2);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+                final View decor = getActivity().getWindow().getDecorView();
+                decor.postOnAnimation(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (twoFramesLatch.getCount() > 0) {
+                            twoFramesLatch.countDown();
+                            decor.postOnAnimation(this);
+                        }
+                    }
+                });
+            }
+        });
+
+        assertTrue("Animation didn't start in a reasonable time",
+                twoFramesLatch.await(100, TimeUnit.MILLISECONDS));
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue("Start value should readjust to current position",
+                        target.getTestValue() != 0);
+                anim.cancel();
+                anim.setupStartValues();
+                anim.start();
+                assertTrue("Start value should readjust to current position",
+                        target.getTestValue() != 0);
+                anim.cancel();
+            }
+        });
+    }
+
     static class AnimTarget {
         private float mTestValue = 0;
 
diff --git a/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java b/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java
index 200ebce..5e23b29 100644
--- a/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java
+++ b/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java
@@ -21,9 +21,14 @@
 import android.animation.Keyframe;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.animation.TypeConverter;
 import android.animation.ValueAnimator;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.PointF;
 import android.graphics.drawable.ShapeDrawable;
 import android.test.ActivityInstrumentationTestCase2;
+import android.util.FloatProperty;
 import android.util.Property;
 import android.view.View;
 import android.view.animation.AccelerateInterpolator;
@@ -33,6 +38,18 @@
 
 public class PropertyValuesHolderTest extends
         ActivityInstrumentationTestCase2<AnimationActivity> {
+    private static final float LINE1_START = -32f;
+    private static final float LINE1_END = -2f;
+    private static final float LINE1_Y = 0f;
+    private static final float LINE2_START = 2f;
+    private static final float LINE2_END = 12f;
+    private static final float QUADRATIC_CTRL_PT1_X = 0f;
+    private static final float QUADRATIC_CTRL_PT1_Y = 0f;
+    private static final float QUADRATIC_CTRL_PT2_X = 50f;
+    private static final float QUADRATIC_CTRL_PT2_Y = 20f;
+    private static final float QUADRATIC_CTRL_PT3_X = 100f;
+    private static final float QUADRATIC_CTRL_PT3_Y = 0f;
+
     private AnimationActivity mActivity;
     private Animator mAnimator;
     private long mDuration = 1000;
@@ -199,7 +216,7 @@
         assertEquals("Animation should run as expected", 100f, mActivity.view.newBall.getY());
     }
 
-    public void testOffloat() throws Throwable {
+    public void testOfFloat() throws Throwable {
         float[] values = {mStartY, mEndY};
         PropertyValuesHolder pVHolder = PropertyValuesHolder.ofFloat(mProperty, values);
         assertNotNull(pVHolder);
@@ -272,10 +289,425 @@
             mDuration);
         startAnimation(objectAnimator, colorAnimator);
         Thread.sleep(1000);
-        Integer i = (Integer) colorAnimator.getAnimatedValue();
-        //We are going from less negative value to a more negative value
-        assertTrue(i.intValue() <= startColor);
-        assertTrue(endColor <= i.intValue());
+        Integer animatedValue = (Integer) colorAnimator.getAnimatedValue();
+        int redMin = Math.min(Color.red(startColor), Color.red(endColor));
+        int redMax = Math.max(Color.red(startColor), Color.red(endColor));
+        int blueMin = Math.min(Color.blue(startColor), Color.blue(endColor));
+        int blueMax = Math.max(Color.blue(startColor), Color.blue(endColor));
+        assertTrue(Color.red(animatedValue) >= redMin);
+        assertTrue(Color.red(animatedValue) <= redMax);
+        assertTrue(Color.blue(animatedValue) >= blueMin);
+        assertTrue(Color.blue(animatedValue) <= blueMax);
+    }
+
+    public void testOfMultiFloat_Path() throws Throwable {
+        // Test for PropertyValuesHolder.ofMultiFloat(String, Path);
+        // Create a quadratic bezier curve that are symmetric about the vertical line (x = 50).
+        // Expect when fraction < 0.5, x < 50, otherwise, x >= 50.
+        Path path = new Path();
+        path.moveTo(QUADRATIC_CTRL_PT1_X, QUADRATIC_CTRL_PT1_Y);
+        path.quadTo(QUADRATIC_CTRL_PT2_X, QUADRATIC_CTRL_PT2_Y,
+                QUADRATIC_CTRL_PT3_X, QUADRATIC_CTRL_PT3_Y);
+
+        PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat("position", path);
+        final ValueAnimator anim = ValueAnimator.ofPropertyValuesHolder(pvh);
+
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.setDuration(200);
+
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            float lastFraction = 0;
+            float lastX = 0;
+            float lastY = 0;
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float[] values = (float[]) animation.getAnimatedValue();
+                assertEquals(2, values.length);
+                float x = values[0];
+                float y = values[1];
+                float fraction = animation.getAnimatedFraction();
+                // Given that the curve is symmetric about the line (x = 50), x should be less than
+                // 50 for half of the animation duration.
+                if (fraction < 0.5) {
+                    assertTrue(x < QUADRATIC_CTRL_PT2_X);
+                } else {
+                    assertTrue(x >= QUADRATIC_CTRL_PT2_X);
+                }
+
+                if (lastFraction > 0.5) {
+                    // x should be increasing, y should be decreasing
+                    assertTrue(x >= lastX);
+                    assertTrue(y <= lastY);
+                } else if (fraction <= 0.5) {
+                    // when fraction <= 0.5, both x, y should be increasing
+                    assertTrue(x >= lastX);
+                    assertTrue(y >= lastY);
+                }
+                lastX = x;
+                lastY = y;
+                lastFraction = fraction;
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(400, TimeUnit.MILLISECONDS));
+    }
+
+    public void testOfMultiFloat_Array() throws Throwable {
+        // Test for PropertyValuesHolder.ofMultiFloat(String, float[][]);
+        final float[][] data = new float[10][];
+        for (int i = 0; i < data.length; i++) {
+            data[i] = new float[3];
+            data[i][0] = i;
+            data[i][1] = i * 2;
+            data[i][2] = 0f;
+        }
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat("position", data);
+
+        final ValueAnimator anim = ValueAnimator.ofPropertyValuesHolder(pvh);
+        anim.setInterpolator(null);
+        anim.setDuration(60);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float fraction = animation.getAnimatedFraction();
+                float[] values = (float[]) animation.getAnimatedValue();
+                assertEquals(3, values.length);
+
+                float expectedX = fraction * (data.length - 1);
+
+                assertEquals(expectedX, values[0]);
+                assertEquals(expectedX * 2, values[1]);
+                assertEquals(0f, values[2]);
+            }
+        });
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    public void testOfMultiInt_Path() throws Throwable {
+        // Test for PropertyValuesHolder.ofMultiInt(String, Path);
+        // Create a quadratic bezier curve that are symmetric about the vertical line (x = 50).
+        // Expect when fraction < 0.5, x < 50, otherwise, x >= 50.
+        Path path = new Path();
+        path.moveTo(QUADRATIC_CTRL_PT1_X, QUADRATIC_CTRL_PT1_Y);
+        path.quadTo(QUADRATIC_CTRL_PT2_X, QUADRATIC_CTRL_PT2_Y,
+                QUADRATIC_CTRL_PT3_X, QUADRATIC_CTRL_PT3_Y);
+
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt("position", path);
+        final ValueAnimator anim = ValueAnimator.ofPropertyValuesHolder(pvh);
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.setDuration(200);
+
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            float lastFraction = 0;
+            int lastX = 0;
+            int lastY = 0;
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                int[] values = (int[]) animation.getAnimatedValue();
+                assertEquals(2, values.length);
+                int x = values[0];
+                int y = values[1];
+                float fraction = animation.getAnimatedFraction();
+                // Given that the curve is symmetric about the line (x = 50), x should be less than
+                // 50 for half of the animation duration.
+                if (fraction < 0.5) {
+                    assertTrue(x < QUADRATIC_CTRL_PT2_X);
+                } else {
+                    assertTrue(x >= QUADRATIC_CTRL_PT2_X);
+                }
+
+                if (lastFraction > 0.5) {
+                    // x should be increasing, y should be decreasing
+                    assertTrue(x >= lastX);
+                    assertTrue(y <= lastY);
+                } else if (fraction <= 0.5) {
+                    // when fraction <= 0.5, both x, y should be increasing
+                    assertTrue(x >= lastX);
+                    assertTrue(y >= lastY);
+                }
+                lastX = x;
+                lastY = y;
+                lastFraction = fraction;
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(400, TimeUnit.MILLISECONDS));
+    }
+
+    public void testOfMultiInt_Array() throws Throwable {
+        // Test for PropertyValuesHolder.ofMultiFloat(String, int[][]);
+        final int[][] data = new int[10][];
+        for (int i = 0; i < data.length; i++) {
+            data[i] = new int[3];
+            data[i][0] = i;
+            data[i][1] = i * 2;
+            data[i][2] = 0;
+        }
+
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt("position", data);
+        final ValueAnimator anim = ValueAnimator.ofPropertyValuesHolder(pvh);
+        anim.setInterpolator(null);
+        anim.setDuration(60);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float fraction = animation.getAnimatedFraction();
+                int[] values = (int[]) animation.getAnimatedValue();
+                assertEquals(3, values.length);
+
+                int expectedX = Math.round(fraction * (data.length - 1));
+                int expectedY = Math.round(fraction * (data.length - 1) * 2);
+
+                // Allow a delta of 1 for rounding errors.
+                assertEquals(expectedX, values[0], 1);
+                assertEquals(expectedY, values[1], 1);
+                assertEquals(0, values[2]);
+            }
+        });
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim.start();
+            }
+        });
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    public void testOfObject_Converter() throws Throwable {
+        // Test for PropertyValuesHolder.ofObject(String, TypeConverter<T, V>, Path)
+        // and for PropertyValuesHolder.ofObject(Property, TypeConverter<T, V>, Path)
+        // Create a path that contains two disconnected line segments. Check that the animated
+        // property x and property y always stay on the line segments.
+        Path path = new Path();
+        path.moveTo(LINE1_START, -LINE1_START);
+        path.lineTo(LINE1_END, -LINE1_END);
+        path.moveTo(LINE2_START, LINE2_START);
+        path.lineTo(LINE2_END, LINE2_END);
+        TypeConverter<PointF, Float> converter = new TypeConverter<PointF, Float>(
+                PointF.class, Float.class) {
+            @Override
+            public Float convert(PointF value) {
+                return (float) Math.sqrt(value.x * value.x + value.y * value.y);
+            }
+        };
+        final CountDownLatch endLatch = new CountDownLatch(3);
+
+        // Create three animators. The first one use a converter that converts the point to distance
+        // to  origin. The second one does not have a type converter. The third animator uses a
+        // converter to changes sign of the x, y value of the input pointF.
+        FloatProperty property = new FloatProperty("distance") {
+            @Override
+            public void setValue(Object object, float value) {
+            }
+
+            @Override
+            public Object get(Object object) {
+                return null;
+            }
+        };
+        final PropertyValuesHolder pvh1 =
+                PropertyValuesHolder.ofObject(property, converter, path);
+        final ValueAnimator anim1 = ValueAnimator.ofPropertyValuesHolder(pvh1);
+        anim1.setDuration(100);
+        anim1.setInterpolator(null);
+        anim1.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        final PropertyValuesHolder pvh2 =
+                PropertyValuesHolder.ofObject("position", null, path);
+        final ValueAnimator anim2 = ValueAnimator.ofPropertyValuesHolder(pvh2);
+        anim2.setDuration(100);
+        anim2.setInterpolator(null);
+        anim2.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        TypeConverter<PointF, PointF> converter3 = new TypeConverter<PointF, PointF>(
+                PointF.class, PointF.class) {
+            PointF mValue = new PointF();
+            @Override
+            public PointF convert(PointF value) {
+                mValue.x = -value.x;
+                mValue.y = -value.y;
+                return mValue;
+            }
+        };
+        final PropertyValuesHolder pvh3 =
+                PropertyValuesHolder.ofObject("position", converter3, path);
+        final ValueAnimator anim3 = ValueAnimator.ofPropertyValuesHolder(pvh3);
+        anim3.setDuration(100);
+        anim3.setInterpolator(null);
+        anim3.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        anim3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            // Set the initial value of the distance to the distance between the first point on
+            // the path to the origin.
+            float mLastDistance = (float) (32 * Math.sqrt(2));
+            float mLastFraction = 0f;
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float fraction = anim1.getAnimatedFraction();
+                assertEquals(fraction, anim2.getAnimatedFraction());
+                assertEquals(fraction, anim3.getAnimatedFraction());
+                float distance = (Float) anim1.getAnimatedValue();
+                PointF position = (PointF) anim2.getAnimatedValue();
+                PointF positionReverseSign = (PointF) anim3.getAnimatedValue();
+                assertEquals(position.x, -positionReverseSign.x);
+                assertEquals(position.y, -positionReverseSign.y);
+
+                // Manually calculate the distance for the animator that doesn't have a
+                // TypeConverter, and expect the result to be the same as the animation value from
+                // the type converter.
+                float distanceFromPosition = (float) Math.sqrt(
+                        position.x * position.x + position.y * position.y);
+                assertEquals(distance, distanceFromPosition, 0.0001f);
+
+                if (mLastFraction > 0.75) {
+                    // In the 2nd line segment of the path, distance to origin should be increasing.
+                    assertTrue(distance >= mLastDistance);
+                } else if (fraction < 0.75) {
+                    assertTrue(distance <= mLastDistance);
+                }
+                mLastDistance = distance;
+                mLastFraction = fraction;
+            }
+        });
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim1.start();
+                anim2.start();
+                anim3.start();
+            }
+        });
+
+        // Wait until both of the animations finish
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    public void testSetConverter() throws Throwable {
+        // Test for PropertyValuesHolder.setConverter()
+        PropertyValuesHolder pvh = PropertyValuesHolder.ofObject("", null, 0f, 1f);
+        // Reverse the sign of the float in the converter, and use that value as the new type
+        // PointF's x value.
+        pvh.setConverter(new TypeConverter<Float, PointF>(Float.class, PointF.class) {
+            PointF mValue = new PointF();
+            @Override
+            public PointF convert(Float value) {
+                mValue.x = value * (-1f);
+                mValue.y = 0f;
+                return mValue;
+            }
+        });
+        final CountDownLatch endLatch = new CountDownLatch(2);
+
+        final ValueAnimator anim1 = ValueAnimator.ofPropertyValuesHolder(pvh);
+        anim1.setInterpolator(null);
+        anim1.setDuration(100);
+        anim1.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        final ValueAnimator anim2 = ValueAnimator.ofFloat(0f, 1f);
+        anim2.setInterpolator(null);
+        anim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                assertEquals(anim1.getAnimatedFraction(), anim2.getAnimatedFraction());
+                // Check that the pvh with type converter did reverse the sign of float, and set
+                // the x value of the PointF with it.
+                PointF value1 = (PointF) anim1.getAnimatedValue();
+                float value2 = (Float) anim2.getAnimatedValue();
+                assertEquals(value2, -value1.x);
+                assertEquals(0f, value1.y);
+            }
+        });
+        anim2.setDuration(100);
+        anim2.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim1.start();
+                anim2.start();
+            }
+        });
+
+        // Wait until both of the animations finish
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
     }
 
     public void testSetProperty() throws Throwable {
diff --git a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
index b778530..b43cc3a 100644
--- a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
@@ -19,6 +19,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.graphics.Color;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.LinearInterpolator;
@@ -393,6 +394,57 @@
         assertTrue(animatedValue <= end);
     }
 
+    public void testOfArgb() throws Throwable {
+        int start = 0xffff0000;
+        int end = 0xff0000ff;
+        int[] values = {start, end};
+        int startRed = Color.red(start);
+        int startBlue = Color.blue(start);
+        int endRed = Color.red(end);
+        int endBlue = Color.blue(end);
+        final ValueAnimator valueAnimatorLocal = ValueAnimator.ofArgb(values);
+        valueAnimatorLocal.setDuration(mDuration);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        valueAnimatorLocal.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                if (animation.getAnimatedFraction() > .05f) {
+                    latch.countDown();
+                }
+            }
+        });
+
+        this.runTestOnUiThread(new Runnable(){
+            public void run() {
+                valueAnimatorLocal.start();
+            }
+        });
+        boolean isRunning = valueAnimatorLocal.isRunning();
+        assertTrue(isRunning);
+
+        assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
+
+        Integer animatedValue = (Integer) valueAnimatorLocal.getAnimatedValue();
+        int alpha = Color.alpha(animatedValue);
+        int red = Color.red(animatedValue);
+        int green = Color.green(animatedValue);
+        int blue = Color.blue(animatedValue);
+        assertTrue(red < startRed);
+        assertTrue(red > endRed);
+        assertTrue(blue > startBlue);
+        assertTrue(blue < endBlue);
+        assertEquals(255, alpha);
+        assertEquals(0, green);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                valueAnimatorLocal.cancel();
+            }
+        });
+    }
+
     public void testNoDelayOnSeekAnimation() throws Throwable {
         ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
         animator.setInterpolator(new LinearInterpolator());
@@ -418,6 +470,31 @@
         });
     }
 
+    public void testNotifiesAfterEnd() throws Throwable {
+        final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                assertTrue(animation.isStarted());
+                assertTrue(animation.isRunning());
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                assertFalse(animation.isRunning());
+                assertFalse(animation.isStarted());
+                super.onAnimationEnd(animation);
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                animator.start();
+                animator.end();
+            }
+        });
+    }
+
     private ValueAnimator getAnimator() {
         Object object = mActivity.view.newBall;
         String property = "y";
diff --git a/tests/tests/app.usage/Android.mk b/tests/tests/app.usage/Android.mk
index 4cc3606..0303dbd 100644
--- a/tests/tests/app.usage/Android.mk
+++ b/tests/tests/app.usage/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
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 bd96d76..2c3c2ad 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
@@ -26,6 +26,9 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
+import android.net.TrafficStats;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
@@ -53,6 +56,12 @@
     private static final long MINUTE = 1000 * 60;
     private static final int TIMEOUT_MILLIS = 15000;
 
+    private static final String CHECK_CONNECTIVITY_URL = "http://www.265.com/";
+    private static final String CHECK_CALLBACK_URL = CHECK_CONNECTIVITY_URL;
+
+    private static final int NETWORK_TAG = 0xf00d;
+    private static final long THRESHOLD_BYTES = 2 * 1024 * 1024;  // 2 MB
+
     private interface NetworkInterfaceToTest {
         int getNetworkType();
         int getTransportType();
@@ -119,7 +128,7 @@
     private String mWriteSettingsMode;
     private String mUsageStatsMode;
 
-    private void exerciseRemoteHost(Network network) throws Exception {
+    private void exerciseRemoteHost(Network network, URL url) throws Exception {
         NetworkInfo networkInfo = mCm.getNetworkInfo(network);
         if (networkInfo == null) {
             Log.w(LOG_TAG, "Network info is null");
@@ -131,8 +140,8 @@
         String originalKeepAlive = System.getProperty("http.keepAlive");
         System.setProperty("http.keepAlive", "false");
         try {
-            urlc = (HttpURLConnection) network.openConnection(new URL(
-                    "http://www.265.com/"));
+            TrafficStats.setThreadStatsTag(NETWORK_TAG);
+            urlc = (HttpURLConnection) network.openConnection(url);
             urlc.setConnectTimeout(TIMEOUT_MILLIS);
             urlc.setUseCaches(false);
             urlc.connect();
@@ -147,6 +156,7 @@
         } catch (Exception e) {
             Log.i(LOG_TAG, "Badness during exercising remote server: " + e);
         } finally {
+            TrafficStats.clearThreadStatsTag();
             if (in != null) {
                 try {
                     in.close();
@@ -229,10 +239,12 @@
 
     private class NetworkCallback extends ConnectivityManager.NetworkCallback {
         private long mTolerance;
+        private URL mUrl;
         public boolean success;
 
-        NetworkCallback(long tolerance) {
+        NetworkCallback(long tolerance, URL url) {
             mTolerance = tolerance;
+            mUrl = url;
             success = false;
         }
 
@@ -240,7 +252,7 @@
         public void onAvailable(Network network) {
             try {
                 mStartTime = System.currentTimeMillis() - mTolerance;
-                exerciseRemoteHost(network);
+                exerciseRemoteHost(network, mUrl);
                 mEndTime = System.currentTimeMillis() + mTolerance;
                 success = true;
                 synchronized(NetworkUsageStatsTest.this) {
@@ -260,7 +272,7 @@
         if (!hasFeature) {
             return false;
         }
-        NetworkCallback callback = new NetworkCallback(tolerance);
+        NetworkCallback callback = new NetworkCallback(tolerance, new URL(CHECK_CONNECTIVITY_URL));
         mCm.requestNetwork(new NetworkRequest.Builder()
                 .addTransportType(sNetworkInterfacesToTest[networkTypeIndex].getTransportType())
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
@@ -520,10 +532,99 @@
         }
     }
 
+    public void testTagDetails() throws Exception {
+        for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
+            // Relatively large tolerance to accommodate for history bucket size.
+            if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
+                continue;
+            }
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
+            NetworkStats result = null;
+            try {
+                result = mNsm.queryDetailsForUidTag(
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
+                        mStartTime, mEndTime, Process.myUid(), NETWORK_TAG);
+                assertTrue(result != null);
+                NetworkStats.Bucket bucket = new NetworkStats.Bucket();
+                long totalTxPackets = 0;
+                long totalRxPackets = 0;
+                long totalTxBytes = 0;
+                long totalRxBytes = 0;
+                while (result.hasNextBucket()) {
+                    assertTrue(result.getNextBucket(bucket));
+                    assertTimestamps(bucket);
+                    assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_ALL);
+                    assertEquals(bucket.getUid(), Process.myUid());
+                    if (bucket.getTag() == NETWORK_TAG) {
+                        totalTxPackets += bucket.getTxPackets();
+                        totalRxPackets += bucket.getRxPackets();
+                        totalTxBytes += bucket.getTxBytes();
+                        totalRxBytes += bucket.getRxBytes();
+                    }
+                }
+                assertTrue("No Rx bytes tagged with 0x" + Integer.toHexString(NETWORK_TAG)
+                        + " for uid " + Process.myUid(), totalRxBytes > 0);
+                assertTrue("No Rx packets tagged with " + Integer.toHexString(NETWORK_TAG)
+                        + " for uid " + Process.myUid(), totalRxPackets > 0);
+                assertTrue("No Tx bytes tagged with 0x" + Integer.toHexString(NETWORK_TAG)
+                        + " for uid " + Process.myUid(), totalTxBytes > 0);
+                assertTrue("No Tx packets tagged with 0x" + Integer.toHexString(NETWORK_TAG)
+                        + " for uid " + Process.myUid(), totalTxPackets > 0);
+            } catch (SecurityException e) {
+                fail("testUidDetails fails with exception: " + e.toString());
+            } finally {
+                if (result != null) {
+                    result.close();
+                }
+            }
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
+            try {
+                result = mNsm.queryDetailsForUidTag(
+                        sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
+                        mStartTime, mEndTime, Process.myUid(), NETWORK_TAG);
+                fail("negative testUidDetails fails: no exception thrown.");
+            } catch (SecurityException e) {
+                // expected outcome
+            }
+        }
+    }
+
+    public void testCallback() throws Exception {
+        for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
+            // Relatively large tolerance to accommodate for history bucket size.
+            if (!shouldTestThisNetworkType(i, MINUTE/2)) {
+                continue;
+            }
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
+
+            TestUsageCallback usageCallback = new TestUsageCallback();
+            HandlerThread thread = new HandlerThread("callback-thread");
+            thread.start();
+            Handler handler = new Handler(thread.getLooper());
+            mNsm.registerUsageCallback(sNetworkInterfacesToTest[i].getNetworkType(),
+                    getSubscriberId(i), THRESHOLD_BYTES, usageCallback, handler);
+
+            // TODO: Force traffic and check whether the callback is invoked.
+            // Right now the test only covers whether the callback can be registered, but not
+            // whether it is invoked upon data usage since we don't have a scalable way of
+            // storing files of >2MB in CTS.
+
+            mNsm.unregisterUsageCallback(usageCallback);
+        }
+    }
+
     private void assertTimestamps(final NetworkStats.Bucket bucket) {
         assertTrue("Start timestamp " + bucket.getStartTimeStamp() + " is less than " +
                 mStartTime, bucket.getStartTimeStamp() >= mStartTime);
         assertTrue("End timestamp " + bucket.getEndTimeStamp() + " is greater than " +
                 mEndTime, bucket.getEndTimeStamp() <= mEndTime);
     }
+
+    private static class TestUsageCallback extends NetworkStatsManager.UsageCallback {
+        @Override
+        public void onThresholdReached(int networkType, String subscriberId) {
+            Log.v(LOG_TAG, "Called onThresholdReached for networkType=" + networkType
+                    + " subscriberId=" + subscriberId);
+        }
+    }
 }
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index d3890df..d900292 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -30,6 +30,7 @@
 import android.test.InstrumentationTestCase;
 
 import java.io.FileInputStream;
+import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.List;
@@ -37,8 +38,6 @@
 
 import android.util.SparseLongArray;
 import junit.framework.AssertionFailedError;
-import libcore.io.IoUtils;
-import libcore.io.Streams;
 import org.junit.Ignore;
 
 /**
@@ -94,7 +93,8 @@
 
     private static void assertLessThanOrEqual(long left, long right) {
         if (left > right) {
-            throw new AssertionFailedError("Expected " + left + " to be less than or equal to " + right);
+            throw new AssertionFailedError("Expected " + left + " to be less than or equal to "
+                    + right);
         }
     }
 
@@ -103,16 +103,23 @@
                 getInstrumentation().getContext().getPackageName(), mode);
         ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
                 .executeShellCommand(command);
-        try {
-            Streams.readFully(new FileInputStream(pfd.getFileDescriptor()));
+        try (FileInputStream fis = new FileInputStream(pfd.getFileDescriptor())){
+            final byte[] buffer = new byte[4096];
+            while (fis.read(buffer) != -1) { }
         } finally {
-            IoUtils.closeQuietly(pfd.getFileDescriptor());
+            try {
+                pfd.close();
+            } catch (IOException e) {
+                // Ignore.
+            }
         }
     }
 
     private void launchSubActivity(Class<? extends Activity> clazz) {
-        final Instrumentation.ActivityResult result = new Instrumentation.ActivityResult(0, new Intent());
-        final Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(clazz.getName(), result, false);
+        final Instrumentation.ActivityResult result =
+                new Instrumentation.ActivityResult(0, new Intent());
+        final Instrumentation.ActivityMonitor monitor =
+                new Instrumentation.ActivityMonitor(clazz.getName(), result, false);
         getInstrumentation().addMonitor(monitor);
         launchActivity(mTargetPackage, clazz, null);
         mStartedActivities.add(monitor.waitForActivity());
@@ -198,7 +205,8 @@
 
         long endTime = System.currentTimeMillis();
         long startTime = endTime - MINUTE;
-        Map<String, UsageStats> statsMap = mUsageStatsManager.queryAndAggregateUsageStats(startTime, endTime);
+        Map<String, UsageStats> statsMap = mUsageStatsManager.queryAndAggregateUsageStats(startTime,
+                endTime);
         assertFalse(statsMap.isEmpty());
         assertTrue(statsMap.containsKey(mTargetPackage));
         final UsageStats before = statsMap.get(mTargetPackage);
@@ -284,20 +292,23 @@
             final int intervalType = intervalLengths.keyAt(i);
             final long intervalDuration = intervalLengths.valueAt(i);
             final long startTime = endTime - (2 * intervalDuration);
-            final List<UsageStats> statsList = mUsageStatsManager.queryUsageStats(intervalType, startTime, endTime);
+            final List<UsageStats> statsList = mUsageStatsManager.queryUsageStats(intervalType,
+                    startTime, endTime);
             assertFalse(statsList.isEmpty());
 
             boolean foundPackage = false;
             for (UsageStats stats : statsList) {
                 // Verify that each period is a day long.
-                assertLessThanOrEqual(stats.getLastTimeStamp() - stats.getFirstTimeStamp(), intervalDuration);
+                assertLessThanOrEqual(stats.getLastTimeStamp() - stats.getFirstTimeStamp(),
+                        intervalDuration);
                 if (stats.getPackageName().equals(mTargetPackage) &&
                         stats.getLastTimeUsed() >= beforeTime - TIME_DIFF_THRESHOLD) {
                     foundPackage = true;
                 }
             }
 
-            assertTrue("Did not find package " + mTargetPackage + " in interval " + intervalType, foundPackage);
+            assertTrue("Did not find package " + mTargetPackage + " in interval " + intervalType,
+                    foundPackage);
         }
     }
 
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
index 08201a6..cf76aa0 100644
--- a/tests/tests/app/Android.mk
+++ b/tests/tests/app/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
index 61b964d..313f009 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
@@ -90,10 +90,10 @@
     }
 
     private static final String GRANT_BIND_APP_WIDGET_PERMISSION_COMMAND =
-            "appwidget grantbind --package android.cts.appwidget --user 0";
+            "appwidget grantbind --package android.appwidget.cts --user 0";
 
     private static final String REVOKE_BIND_APP_WIDGET_PERMISSION_COMMAND =
-            "appwidget revokebind --package android.cts.appwidget --user 0";
+            "appwidget revokebind --package android.appwidget.cts --user 0";
 
 
     private boolean hasAppWidgets() {
diff --git a/tests/tests/car/Android.mk b/tests/tests/car/Android.mk
index 0138317..cebd099 100644
--- a/tests/tests/car/Android.mk
+++ b/tests/tests/car/Android.mk
@@ -24,7 +24,7 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
 LOCAL_JAVA_LIBRARIES := android.car
 
diff --git a/tests/tests/car/src/android/car/cts/CarAppContextManagerTest.java b/tests/tests/car/src/android/car/cts/CarAppContextManagerTest.java
deleted file mode 100644
index dffdd3e..0000000
--- a/tests/tests/car/src/android/car/cts/CarAppContextManagerTest.java
+++ /dev/null
@@ -1,238 +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.car.cts;
-
-import android.car.Car;
-import android.car.CarAppContextManager;
-import android.util.Log;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-public class CarAppContextManagerTest extends CarApiTestBase {
-    private static final String TAG = CarAppContextManager.class.getSimpleName();
-    private CarAppContextManager mManager;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mManager = (CarAppContextManager) getCar().getCarManager(Car.APP_CONTEXT_SERVICE);
-        assertNotNull(mManager);
-    }
-
-    public void testSetActiveNullListener() throws Exception {
-        try {
-            mManager.setActiveContexts(null, CarAppContextManager.APP_CONTEXT_NAVIGATION);
-            fail();
-        } catch (IllegalStateException e) {
-            // Expected.
-        }
-    }
-
-    public void testRegisterNull() throws Exception {
-        try {
-            mManager.registerContextListener(null, 0);
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected.
-        }
-    }
-
-    public void testRegisterUnregister() throws Exception {
-        ContextChangeListener listener = new ContextChangeListener();
-        ContextChangeListener listener2 = new ContextChangeListener();
-        mManager.registerContextListener(listener, 0);
-        mManager.registerContextListener(listener2, 0);
-        mManager.unregisterContextListener();
-        // this one is no-op
-        mManager.unregisterContextListener();
-    }
-
-    public void testContextChange() throws Exception {
-        DefaultServiceConnectionListener connectionListener =
-                new DefaultServiceConnectionListener();
-        Car car2 = Car.createCar(getContext(), connectionListener, null);
-        car2.connect();
-        connectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
-        CarAppContextManager manager2 = (CarAppContextManager)
-                car2.getCarManager(Car.APP_CONTEXT_SERVICE);
-        assertNotNull(manager2);
-
-        assertEquals(0, mManager.getActiveAppContexts());
-        ContextChangeListener change = new ContextChangeListener();
-        ContextChangeListener change2 = new ContextChangeListener();
-        ContextOwnershipChangeListener owner = new ContextOwnershipChangeListener();
-        ContextOwnershipChangeListener owner2 = new ContextOwnershipChangeListener();
-        mManager.registerContextListener(change, CarAppContextManager.APP_CONTEXT_NAVIGATION |
-                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
-        manager2.registerContextListener(change2, CarAppContextManager.APP_CONTEXT_NAVIGATION |
-                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
-
-        mManager.setActiveContexts(owner, CarAppContextManager.APP_CONTEXT_NAVIGATION);
-        int expectedContexts = CarAppContextManager.APP_CONTEXT_NAVIGATION;
-        assertEquals(expectedContexts, mManager.getActiveAppContexts());
-        assertEquals(expectedContexts, manager2.getActiveAppContexts());
-        assertTrue(mManager.isOwningContext(expectedContexts));
-        assertFalse(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertFalse(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION |
-                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertFalse(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertFalse(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertTrue(change2.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                expectedContexts));
-        // change should not get notification for its own change
-        assertFalse(change.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 0));
-
-        mManager.setActiveContexts(owner, CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
-        expectedContexts = CarAppContextManager.APP_CONTEXT_NAVIGATION |
-                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND;
-        assertTrue(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertTrue(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertTrue(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION |
-                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertFalse(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertFalse(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertEquals(expectedContexts, mManager.getActiveAppContexts());
-        assertEquals(expectedContexts, manager2.getActiveAppContexts());
-        assertTrue(change2.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                expectedContexts));
-        // change should not get notification for its own change
-        assertFalse(change.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 0));
-
-        // this should be no-op
-        mManager.setActiveContexts(owner, CarAppContextManager.APP_CONTEXT_NAVIGATION);
-        assertEquals(expectedContexts, mManager.getActiveAppContexts());
-        assertEquals(expectedContexts, manager2.getActiveAppContexts());
-        assertFalse(change2.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 0));
-        assertFalse(change.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 0));
-
-        manager2.setActiveContexts(owner2, CarAppContextManager.APP_CONTEXT_NAVIGATION);
-        assertFalse(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertTrue(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertTrue(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertFalse(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertEquals(expectedContexts, mManager.getActiveAppContexts());
-        assertEquals(expectedContexts, manager2.getActiveAppContexts());
-        assertTrue(owner.waitForOwnershipLossAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                CarAppContextManager.APP_CONTEXT_NAVIGATION));
-
-        // no-op as it is not owning it
-        mManager.resetActiveContexts(CarAppContextManager.APP_CONTEXT_NAVIGATION);
-        assertFalse(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertTrue(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertTrue(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertFalse(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertEquals(expectedContexts, mManager.getActiveAppContexts());
-        assertEquals(expectedContexts, manager2.getActiveAppContexts());
-
-        mManager.resetActiveContexts(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
-        assertFalse(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertFalse(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertTrue(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertFalse(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        expectedContexts = CarAppContextManager.APP_CONTEXT_NAVIGATION;
-        assertEquals(expectedContexts, mManager.getActiveAppContexts());
-        assertEquals(expectedContexts, manager2.getActiveAppContexts());
-        assertTrue(change2.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertFalse(change.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 0));
-
-        manager2.resetActiveContexts(CarAppContextManager.APP_CONTEXT_NAVIGATION);
-        assertFalse(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertFalse(mManager.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        assertFalse(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        assertFalse(manager2.isOwningContext(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND));
-        expectedContexts = 0;
-        assertEquals(expectedContexts, mManager.getActiveAppContexts());
-        assertEquals(expectedContexts, manager2.getActiveAppContexts());
-        assertTrue(change.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 0));
-        mManager.unregisterContextListener();
-        manager2.unregisterContextListener();
-    }
-
-    public void testFilter() throws Exception {
-        DefaultServiceConnectionListener connectionListener =
-                new DefaultServiceConnectionListener();
-        Car car2 = Car.createCar(getContext(), connectionListener);
-        car2.connect();
-        connectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
-        CarAppContextManager manager2 = (CarAppContextManager)
-                car2.getCarManager(Car.APP_CONTEXT_SERVICE);
-        assertNotNull(manager2);
-
-        assertEquals(0, mManager.getActiveAppContexts());
-        ContextChangeListener change = new ContextChangeListener();
-        ContextChangeListener listener = new ContextChangeListener();
-        ContextOwnershipChangeListener owner = new ContextOwnershipChangeListener();
-        mManager.registerContextListener(change, CarAppContextManager.APP_CONTEXT_NAVIGATION |
-                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
-        manager2.registerContextListener(listener, CarAppContextManager.APP_CONTEXT_NAVIGATION);
-        mManager.setActiveContexts(owner, CarAppContextManager.APP_CONTEXT_NAVIGATION);
-        assertTrue(listener.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
-                CarAppContextManager.APP_CONTEXT_NAVIGATION));
-        mManager.setActiveContexts(owner, CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
-        assertFalse(listener.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 0));
-        mManager.resetActiveContexts(CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
-        assertFalse(listener.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 0));
-        mManager.resetActiveContexts(CarAppContextManager.APP_CONTEXT_NAVIGATION);
-        assertTrue(listener.waitForContextChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 0));
-    }
-
-    private class ContextChangeListener implements CarAppContextManager.AppContextChangeListener {
-        private int mLastChangeEvent;
-        private final Semaphore mChangeWait = new Semaphore(0);
-
-        public boolean waitForContextChangeAndAssert(long timeoutMs, int expectedContexts)
-                throws Exception {
-            if (!mChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
-                return false;
-            }
-            assertEquals(expectedContexts, mLastChangeEvent);
-            return true;
-        }
-
-        @Override
-        public void onAppContextChange(int activeContexts) {
-            Log.i(TAG, "onAppContextChange " + Integer.toHexString(activeContexts));
-            assertMainThread();
-            mLastChangeEvent = activeContexts;
-            mChangeWait.release();
-        }
-    }
-
-    private class ContextOwnershipChangeListener
-            implements CarAppContextManager.AppContextOwnershipChangeListener {
-        private int mLastLossEvent;
-        private final Semaphore mLossEventWait = new Semaphore(0);
-
-        public boolean waitForOwnershipLossAndAssert(long timeoutMs, int expectedContexts)
-                throws Exception {
-            if (!mLossEventWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
-                return false;
-            }
-            assertEquals(expectedContexts, mLastLossEvent);
-            return true;
-        }
-
-        @Override
-        public void onAppContextOwnershipLoss(int context) {
-            Log.i(TAG, "onAppContextOwnershipLoss " + Integer.toHexString(context));
-            assertMainThread();
-            mLastLossEvent = context;
-            mLossEventWait.release();
-        }
-    }
-}
diff --git a/tests/tests/car/src/android/car/cts/CarAppFocusManagerTest.java b/tests/tests/car/src/android/car/cts/CarAppFocusManagerTest.java
new file mode 100644
index 0000000..83fa276
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/CarAppFocusManagerTest.java
@@ -0,0 +1,331 @@
+/*
+ * 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.car.cts;
+
+import android.car.Car;
+import android.car.CarAppFocusManager;
+import android.util.Log;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Assert;
+
+public class CarAppFocusManagerTest extends CarApiTestBase {
+    private static final String TAG = CarAppFocusManagerTest.class.getSimpleName();
+    private CarAppFocusManager mManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mManager = (CarAppFocusManager) getCar().getCarManager(Car.APP_FOCUS_SERVICE);
+        assertNotNull(mManager);
+
+        // Request all application focuses and abandon them to ensure no active context is present
+        // when test starts.
+        FocusOwnershipChangeListerner owner = new FocusOwnershipChangeListerner();
+        mManager.requestAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mManager.requestAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        mManager.abandonAppFocus(owner);
+    }
+
+    public void testSetActiveNullListener() throws Exception {
+        try {
+            mManager.requestAppFocus(null, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    public void testRegisterNull() throws Exception {
+        try {
+            mManager.registerFocusListener(null, 0);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    public void testRegisterUnregister() throws Exception {
+        FocusChangeListerner listener = new FocusChangeListerner();
+        FocusChangeListerner listener2 = new FocusChangeListerner();
+        mManager.registerFocusListener(listener, 1);
+        mManager.registerFocusListener(listener2, 1);
+        mManager.unregisterFocusListener(listener);
+        mManager.unregisterFocusListener(listener2);
+    }
+
+    public void testFocusChange() throws Exception {
+        DefaultServiceConnectionListener connectionListener =
+                new DefaultServiceConnectionListener();
+        Car car2 = Car.createCar(getContext(), connectionListener, null);
+        car2.connect();
+        connectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
+        CarAppFocusManager manager2 = (CarAppFocusManager)
+                car2.getCarManager(Car.APP_FOCUS_SERVICE);
+        assertNotNull(manager2);
+        final int[] emptyFocus = new int[0];
+
+        Assert.assertArrayEquals(emptyFocus, mManager.getActiveAppTypes());
+        FocusChangeListerner change = new FocusChangeListerner();
+        FocusChangeListerner change2 = new FocusChangeListerner();
+        FocusOwnershipChangeListerner owner = new FocusOwnershipChangeListerner();
+        FocusOwnershipChangeListerner owner2 = new FocusOwnershipChangeListerner();
+        mManager.registerFocusListener(change, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mManager.registerFocusListener(change, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        manager2.registerFocusListener(change2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        manager2.registerFocusListener(change2, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+
+        mManager.requestAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        int[] expectedFocuses = new int[] {CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION};
+        Assert.assertArrayEquals(expectedFocuses, mManager.getActiveAppTypes());
+        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        assertTrue(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertFalse(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        assertFalse(manager2.isOwningFocus(owner2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertFalse(manager2.isOwningFocus(owner2,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        assertTrue(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+        assertTrue(change.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+
+        mManager.requestAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        expectedFocuses = new int[] {
+            CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION,
+            CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND };
+        assertTrue(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertTrue(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        assertFalse(manager2.isOwningFocus(owner2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertFalse(manager2.isOwningFocus(owner2,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        Assert.assertArrayEquals(expectedFocuses, mManager.getActiveAppTypes());
+        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        assertTrue(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+        assertTrue(change.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+
+        // this should be no-op
+        change.reset();
+        change2.reset();
+        mManager.requestAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        Assert.assertArrayEquals(expectedFocuses, mManager.getActiveAppTypes());
+        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        assertFalse(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+        assertFalse(change.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+
+        manager2.requestAppFocus(owner2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        assertFalse(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertTrue(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        assertTrue(manager2.isOwningFocus(owner2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertFalse(manager2.isOwningFocus(owner2,
+              CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        Assert.assertArrayEquals(expectedFocuses, mManager.getActiveAppTypes());
+        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        assertTrue(owner.waitForOwnershipLossAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+
+        // no-op as it is not owning it
+        change.reset();
+        change2.reset();
+        mManager.abandonAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        assertFalse(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertTrue(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        assertTrue(manager2.isOwningFocus(owner2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertFalse(manager2.isOwningFocus(owner2,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        Assert.assertArrayEquals(expectedFocuses, mManager.getActiveAppTypes());
+        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+
+        change.reset();
+        change2.reset();
+        mManager.abandonAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        assertFalse(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertFalse(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        assertTrue(manager2.isOwningFocus(owner2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertFalse(manager2.isOwningFocus(owner2,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        expectedFocuses = new int[] {CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION};
+        Assert.assertArrayEquals(expectedFocuses, mManager.getActiveAppTypes());
+        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        assertTrue(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, false));
+        assertTrue(change.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, false));
+
+        change.reset();
+        change2.reset();
+        manager2.abandonAppFocus(owner2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        assertFalse(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertFalse(mManager.isOwningFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        assertFalse(manager2.isOwningFocus(owner2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
+        assertFalse(manager2.isOwningFocus(owner2,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND));
+        expectedFocuses = emptyFocus;
+        Assert.assertArrayEquals(expectedFocuses, mManager.getActiveAppTypes());
+        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        assertTrue(change.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+        mManager.unregisterFocusListener(change);
+        manager2.unregisterFocusListener(change2);
+    }
+
+    public void testFilter() throws Exception {
+        DefaultServiceConnectionListener connectionListener =
+                new DefaultServiceConnectionListener();
+        Car car2 = Car.createCar(getContext(), connectionListener);
+        car2.connect();
+        connectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
+        CarAppFocusManager manager2 = (CarAppFocusManager)
+                car2.getCarManager(Car.APP_FOCUS_SERVICE);
+        assertNotNull(manager2);
+
+        Assert.assertArrayEquals(new int[0], mManager.getActiveAppTypes());
+
+        FocusChangeListerner listener = new FocusChangeListerner();
+        FocusChangeListerner listener2 = new FocusChangeListerner();
+        FocusOwnershipChangeListerner owner = new FocusOwnershipChangeListerner();
+        mManager.registerFocusListener(listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mManager.registerFocusListener(listener, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        manager2.registerFocusListener(listener2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+
+        mManager.requestAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+        assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+
+        listener.reset();
+        listener2.reset();
+        mManager.requestAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+        assertFalse(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+
+        listener.reset();
+        listener2.reset();
+        mManager.abandonAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, false));
+        assertFalse(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, false));
+
+        listener.reset();
+        listener2.reset();
+        mManager.abandonAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+        assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+    }
+
+    public void testMultipleChangeListenersPerManager() throws Exception {
+        FocusChangeListerner listener = new FocusChangeListerner();
+        FocusChangeListerner listener2 = new FocusChangeListerner();
+        FocusOwnershipChangeListerner owner = new FocusOwnershipChangeListerner();
+        mManager.registerFocusListener(listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mManager.registerFocusListener(listener, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        mManager.registerFocusListener(listener2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+
+        mManager.requestAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+        assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+
+        listener.reset();
+        listener2.reset();
+        mManager.requestAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+        assertFalse(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+
+        listener.reset();
+        listener2.reset();
+        mManager.abandonAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, false));
+        assertFalse(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, false));
+
+        listener.reset();
+        listener2.reset();
+        mManager.abandonAppFocus(owner, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+        assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+    }
+
+    private class FocusChangeListerner implements CarAppFocusManager.AppFocusChangeListener {
+        private int mLastChangeAppType;
+        private boolean mLastChangeAppActive;
+        private final Semaphore mChangeWait = new Semaphore(0);
+
+        public boolean waitForFocusChangeAndAssert(long timeoutMs, int expectedAppType,
+                boolean expectedAppActive) throws Exception {
+            if (!mChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
+                return false;
+            }
+            assertEquals(expectedAppType, mLastChangeAppType);
+            assertEquals(expectedAppActive, mLastChangeAppActive);
+            return true;
+        }
+
+        public void reset() {
+            mLastChangeAppType = 0;
+            mLastChangeAppActive = false;
+        }
+
+        @Override
+        public void onAppFocusChange(int appType, boolean active) {
+            Log.i(TAG, "onAppFocusChange appType=" + appType + " active=" + active);
+            assertMainThread();
+            mLastChangeAppType = appType;
+            mLastChangeAppActive = active;
+            mChangeWait.release();
+        }
+    }
+
+    private class FocusOwnershipChangeListerner
+            implements CarAppFocusManager.AppFocusOwnershipChangeListener {
+        private int mLastLossEvent;
+        private final Semaphore mLossEventWait = new Semaphore(0);
+
+        public boolean waitForOwnershipLossAndAssert(long timeoutMs, int expectedAppType)
+                throws Exception {
+            if (!mLossEventWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
+                return false;
+            }
+            assertEquals(expectedAppType, mLastLossEvent);
+            return true;
+        }
+
+        @Override
+        public void onAppFocusOwnershipLoss(int appType) {
+            Log.i(TAG, "onAppFocusOwnershipLoss " + appType);
+            assertMainThread();
+            mLastLossEvent = appType;
+            mLossEventWait.release();
+        }
+    }
+}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index d7fb5b7..1a66442 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -108,4 +108,27 @@
         }
     }
 
+    public void testGetIccAuthentication() {
+        // EAP-SIM rand is 16 bytes.
+        String base64Challenge = "ECcTqwuo6OfY8ddFRboD9WM=";
+        String base64Challenge2 = "EMNxjsFrPCpm+KcgCmQGnwQ=";
+        if (!hasCellular) return;
+        try {
+            assertNull("getIccAuthentication should return null for empty data.",
+                    mTelephonyManager.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                    TelephonyManager.AUTHTYPE_EAP_AKA, ""));
+            String response = mTelephonyManager.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                    TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
+            assertTrue("Response to EAP-SIM Challenge must not be Null.", response != null);
+            // response is base64 encoded. After decoding, the value should be:
+            // 1 length byte + SRES(4 bytes) + 1 length byte + Kc(8 bytes)
+            byte[] result = android.util.Base64.decode(response, android.util.Base64.DEFAULT);
+            assertTrue("Result length must be 14 bytes.", 14 == result.length);
+            String response2 = mTelephonyManager.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                    TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge2);
+            assertTrue("Two responses must be different.", !response.equals(response2));
+        } catch (SecurityException e) {
+            failMessage();
+        }
+    }
 }
diff --git a/tests/tests/content/Android.mk b/tests/tests/content/Android.mk
index a22d539..73191c3 100644
--- a/tests/tests/content/Android.mk
+++ b/tests/tests/content/Android.mk
@@ -26,9 +26,16 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctsdeviceutil ctstestrunner services.core
 
 # Resource unit tests use a private locale and some densities
-LOCAL_AAPT_FLAGS = -c xx_YY -c cs -c small -c normal -c large -c xlarge \
+LOCAL_AAPT_FLAGS = -c small -c normal -c large -c xlarge \
         -c 320dpi -c 240dpi -c 160dpi -c 32dpi \
-        -c kok,kok_IN,kok_419,kok_419_VARIANT,kok_Knda_419,kok_Knda_419_VARIANT,kok_VARIANT,kok_Knda,tgl,tgl_PH
+        -c cs \
+        -c fil,fil_SA \
+        -c iw,iw_IL \
+        -c kok,kok_IN,kok_419,kok_419_VARIANT,kok_Knda_419,kok_Knda_419_VARIANT,kok_VARIANT,kok_Knda \
+        -c mk,mk_MK \
+        -c tgl,tgl_PH \
+        -c tlh \
+        -c xx_YY
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/content/res/values-b+fil+SA/configVarying.xml b/tests/tests/content/res/values-b+fil+SA/configVarying.xml
new file mode 100644
index 0000000..ba3c653
--- /dev/null
+++ b/tests/tests/content/res/values-b+fil+SA/configVarying.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag fil SA</item>
+    </bag>
+</resources>
diff --git a/tests/tests/content/res/values-b+fil/configVarying.xml b/tests/tests/content/res/values-b+fil/configVarying.xml
new file mode 100644
index 0000000..2fa8f9f
--- /dev/null
+++ b/tests/tests/content/res/values-b+fil/configVarying.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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>
+    <item type="configVarying" name="simple">simple fil</item>
+</resources>
diff --git a/tests/tests/content/res/values-b+tlh/configVarying.xml b/tests/tests/content/res/values-b+tlh/configVarying.xml
new file mode 100644
index 0000000..48730f3
--- /dev/null
+++ b/tests/tests/content/res/values-b+tlh/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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>
+    <item type="configVarying" name="simple">simple tlh</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag tlh</item>
+    </bag>
+</resources>
diff --git a/tests/tests/content/res/values-iw-rIL/configVarying.xml b/tests/tests/content/res/values-iw-rIL/configVarying.xml
new file mode 100644
index 0000000..a42f026
--- /dev/null
+++ b/tests/tests/content/res/values-iw-rIL/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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>
+    <item type="configVarying" name="simple">simple iw IL</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag iw IL</item>
+    </bag>
+</resources>
diff --git a/tests/tests/content/res/values-iw/configVarying.xml b/tests/tests/content/res/values-iw/configVarying.xml
new file mode 100644
index 0000000..8eabd93
--- /dev/null
+++ b/tests/tests/content/res/values-iw/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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>
+    <item type="configVarying" name="simple">simple iw</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag iw</item>
+    </bag>
+</resources>
diff --git a/tests/tests/content/res/values-mk-rMK/configVarying.xml b/tests/tests/content/res/values-mk-rMK/configVarying.xml
new file mode 100644
index 0000000..14265ef
--- /dev/null
+++ b/tests/tests/content/res/values-mk-rMK/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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>
+    <item type="configVarying" name="simple">simple mk MK</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag mk MK</item>
+    </bag>
+</resources>
diff --git a/tests/tests/content/res/values-mk/configVarying.xml b/tests/tests/content/res/values-mk/configVarying.xml
new file mode 100644
index 0000000..edd1099
--- /dev/null
+++ b/tests/tests/content/res/values-mk/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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>
+    <item type="configVarying" name="simple">simple mk</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag mk</item>
+    </bag>
+</resources>
diff --git a/tests/tests/content/res/values/resources_test.xml b/tests/tests/content/res/values/resources_test.xml
index 91c2c4a..7838518 100644
--- a/tests/tests/content/res/values/resources_test.xml
+++ b/tests/tests/content/res/values/resources_test.xml
@@ -22,6 +22,10 @@
           will be displayed in the app launcher and elsewhere. -->
      <dimen name="app_icon_size">48px</dimen>
      <dimen name="toast_y_offset">64dip</dimen>
+    <dimen name="pos_dimen_149">1.49px</dimen>
+    <dimen name="pos_dimen_151">1.51px</dimen>
+    <dimen name="neg_dimen_149">-1.49px</dimen>
+    <dimen name="neg_dimen_151">-1.51px</dimen>
      <plurals name="plurals_test">
         <item quantity="one">A dog</item>
         <item quantity="other">Some dogs</item>
diff --git a/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java b/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java
index 4893ec1..1387be0 100644
--- a/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java
+++ b/tests/tests/content/src/android/content/res/cts/AssetManagerTest.java
@@ -139,13 +139,16 @@
     public void testGetNonSystemLocales() {
         // This is the list of locales built into this test package. It is basically the locales
         // specified in the Android.mk files (assuming they have corresponding resources), plus the
-        // special case for Filipino.
+        // special cases for Filipino.
         final String KNOWN_LOCALES[] = {
             "cs",
             "fil",
             "fil-PH",
+            "fil-SA",
             "fr",
             "fr-FR",
+            "iw",
+            "iw-IL",
             "kok",
             "kok-419",
             "kok-419-variant",
@@ -154,8 +157,11 @@
             "kok-Knda-419",
             "kok-Knda-419-variant",
             "kok-variant",
+            "mk",
+            "mk-MK",
             "tgl",
             "tgl-PH",
+            "tlh",
             "xx",
             "xx-YY"
         };
diff --git a/tests/tests/content/src/android/content/res/cts/ConfigTest.java b/tests/tests/content/src/android/content/res/cts/ConfigTest.java
index 2390146..912de38 100644
--- a/tests/tests/content/src/android/content/res/cts/ConfigTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ConfigTest.java
@@ -1153,6 +1153,42 @@
     }
 
     @MediumTest
+    public void testNormalLocales() {
+        Resources res;
+        TotalConfig config = makeClassicConfig();
+        // Hebrew
+        config.setProperty(Properties.LANGUAGE, "iw");
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple iw");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag iw"});
+
+        // Hebrew for Israel
+        config.setProperty(Properties.LANGUAGE, "iw");
+        config.setProperty(Properties.COUNTRY, "IL");
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple iw IL");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag iw IL"});
+
+        config = makeClassicConfig();
+        // Macedonian
+        config.setProperty(Properties.LANGUAGE, "mk");
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple mk");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag mk"});
+
+        // Macedonian for Macedonia
+        config.setProperty(Properties.LANGUAGE, "mk");
+        config.setProperty(Properties.COUNTRY, "MK");
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple mk MK");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag mk MK"});
+    }
+
+    @MediumTest
     public void testExtendedLocales() {
         TotalConfig config = makeClassicConfig();
         // BCP 47 Locale kok
@@ -1225,9 +1261,9 @@
         config.setProperty(Properties.LANGUAGE, "fil");
         config.setProperty(Properties.COUNTRY, "US");
         Resources res = config.getResources();
-        checkValue(res, R.configVarying.simple, "simple tl");
+        checkValue(res, R.configVarying.simple, "simple fil");  // We have this resource in 'fil'
         checkValue(res, R.configVarying.bag,
-                R.styleable.TestConfig, new String[] { "bag tl" });
+                R.styleable.TestConfig, new String[] { "bag tl" });  // But this comes from 'tl'
 
         // Ensure that "fil-PH" is mapped to "tl-PH" correctly.
         config = makeClassicConfig();
@@ -1238,6 +1274,24 @@
         checkValue(res, R.configVarying.bag,
                 R.styleable.TestConfig, new String[] { "bag tl PH" });
 
+        // Ensure that "fil-SA" works with no "tl" version.
+        config = makeClassicConfig();
+        config.setProperty(Properties.LANGUAGE, "fil");
+        config.setProperty(Properties.COUNTRY, "SA");
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple fil");  // This comes from 'fil'
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[] { "bag fil SA" });  // And this from 'fil-SA'
+
+        // Ensure that "tlh" is not mistakenly treated as a "tl" variant.
+        config = makeClassicConfig();
+        config.setProperty(Properties.LANGUAGE, "tlh");
+        config.setProperty(Properties.COUNTRY, "US");
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple tlh");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[] { "bag tlh" });
+
         config = makeClassicConfig();
         config.setProperty(Properties.LANGUAGE, "tgl");
         res = config.getResources();
@@ -1276,8 +1330,9 @@
         }
 
         assertEquals(0, tlLocales.size());
-        assertEquals(2, filLocales.size());
+        assertEquals(3, filLocales.size());
         assertTrue(filLocales.contains("fil"));
         assertTrue(filLocales.contains("fil-PH"));
+        assertTrue(filLocales.contains("fil-SA"));
     }
 }
diff --git a/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java b/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
index dbc3e21..12e4f73 100644
--- a/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
@@ -34,6 +34,7 @@
     protected void setUp() throws Exception {
         super.setUp();
         mConfigDefault = new Configuration();
+        mConfigDefault.setToDefaults();
         makeConfiguration();
     }
 
@@ -312,11 +313,60 @@
     }
 
     public void testSetToDefaults() {
-        final Configuration temp = new Configuration(mConfig);
-        assertFalse(temp.equals(mConfigDefault));
-        temp.setToDefaults();
-        assertTrue(temp.equals(mConfigDefault));
-        assertTrue(temp.getLocales().isEmpty());
+        final Configuration config = new Configuration(mConfig);
+        assertFalse(config.equals(mConfigDefault));
+
+        config.setToDefaults();
+        assertTrue(config.equals(mConfigDefault));
+
+        assertEquals(1.0f, config.fontScale);
+        assertEquals(0, config.mcc);
+        assertEquals(0, config.mnc);
+        assertTrue(config.getLocales().isEmpty());
+        assertEquals(null, config.locale);
+        assertFalse(config.userSetLocale);
+        assertEquals(Configuration.TOUCHSCREEN_UNDEFINED, config.touchscreen);
+        assertEquals(Configuration.KEYBOARD_UNDEFINED, config.keyboard);
+        assertEquals(Configuration.KEYBOARDHIDDEN_UNDEFINED, config.keyboardHidden);
+        assertEquals(Configuration.HARDKEYBOARDHIDDEN_UNDEFINED, config.hardKeyboardHidden);
+        assertEquals(Configuration.NAVIGATION_UNDEFINED, config.navigation);
+        assertEquals(Configuration.NAVIGATIONHIDDEN_UNDEFINED, config.navigationHidden);
+        assertEquals(Configuration.ORIENTATION_UNDEFINED, config.orientation);
+        assertEquals(Configuration.SCREENLAYOUT_UNDEFINED, config.screenLayout);
+        assertEquals(Configuration.UI_MODE_TYPE_UNDEFINED, config.uiMode);
+        assertEquals(Configuration.SCREEN_WIDTH_DP_UNDEFINED, config.screenWidthDp);
+        assertEquals(Configuration.SCREEN_WIDTH_DP_UNDEFINED, config.compatScreenWidthDp);
+        assertEquals(Configuration.SCREEN_HEIGHT_DP_UNDEFINED, config.screenHeightDp);
+        assertEquals(Configuration.SCREEN_HEIGHT_DP_UNDEFINED, config.compatScreenHeightDp);
+        assertEquals(Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED,
+                config.smallestScreenWidthDp);
+        assertEquals(Configuration.DENSITY_DPI_UNDEFINED, config.densityDpi);
+    }
+
+    public void testUnset() {
+        Configuration config = new Configuration();
+        assertEquals(0.0f, config.fontScale);
+        assertEquals(0, config.mcc);
+        assertEquals(0, config.mnc);
+        assertTrue(config.getLocales().isEmpty());
+        assertEquals(null, config.locale);
+        assertFalse(config.userSetLocale);
+        assertEquals(Configuration.TOUCHSCREEN_UNDEFINED, config.touchscreen);
+        assertEquals(Configuration.KEYBOARD_UNDEFINED, config.keyboard);
+        assertEquals(Configuration.KEYBOARDHIDDEN_UNDEFINED, config.keyboardHidden);
+        assertEquals(Configuration.HARDKEYBOARDHIDDEN_UNDEFINED, config.hardKeyboardHidden);
+        assertEquals(Configuration.NAVIGATION_UNDEFINED, config.navigation);
+        assertEquals(Configuration.NAVIGATIONHIDDEN_UNDEFINED, config.navigationHidden);
+        assertEquals(Configuration.ORIENTATION_UNDEFINED, config.orientation);
+        assertEquals(Configuration.SCREENLAYOUT_UNDEFINED, config.screenLayout);
+        assertEquals(Configuration.UI_MODE_TYPE_UNDEFINED, config.uiMode);
+        assertEquals(Configuration.SCREEN_WIDTH_DP_UNDEFINED, config.screenWidthDp);
+        assertEquals(Configuration.SCREEN_WIDTH_DP_UNDEFINED, config.compatScreenWidthDp);
+        assertEquals(Configuration.SCREEN_HEIGHT_DP_UNDEFINED, config.screenHeightDp);
+        assertEquals(Configuration.SCREEN_HEIGHT_DP_UNDEFINED, config.compatScreenHeightDp);
+        assertEquals(Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED,
+                config.smallestScreenWidthDp);
+        assertEquals(Configuration.DENSITY_DPI_UNDEFINED, config.densityDpi);
     }
 
     public void testToString() {
diff --git a/tests/tests/content/src/android/content/res/cts/ResourcesTest.java b/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
index 0f40ebd..0c51099 100644
--- a/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
@@ -288,6 +288,10 @@
         // app_icon_size is 48px, as defined in cts/tests/res/values/resources_test.xml
         final int size = mResources.getDimensionPixelSize(R.dimen.app_icon_size);
         assertEquals(48, size);
+        assertEquals(1, mResources.getDimensionPixelSize(R.dimen.pos_dimen_149));
+        assertEquals(2, mResources.getDimensionPixelSize(R.dimen.pos_dimen_151));
+        assertEquals(-1, mResources.getDimensionPixelSize(R.dimen.neg_dimen_149));
+        assertEquals(-2, mResources.getDimensionPixelSize(R.dimen.neg_dimen_151));
     }
 
     public void testGetDrawable() {
diff --git a/tests/tests/graphics/Android.mk b/tests/tests/graphics/Android.mk
index 7e26e07..40beee6 100644
--- a/tests/tests/graphics/Android.mk
+++ b/tests/tests/graphics/Android.mk
@@ -22,7 +22,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-annotations android-support-test mockito-target ctsdeviceutil ctstestrunner
 LOCAL_JNI_SHARED_LIBRARIES := libctsgraphics_jni
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png
new file mode 100644
index 0000000..e74c181
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/avd_empty_animator.xml b/tests/tests/graphics/res/drawable/avd_empty_animator.xml
new file mode 100644
index 0000000..cf6dd9a
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/avd_empty_animator.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+                 xmlns:android="http://schemas.android.com/apk/res/android">
+    <aapt:attr name="android:drawable">
+        <vector
+                android:width="32dp"
+                android:viewportWidth="32"
+                android:height="32dp"
+                android:viewportHeight="32">
+            <group
+                    android:name="btn_radio_to_off_mtrl_0"
+                    android:translateX="16"
+                    android:translateY="16">
+                <group
+                        android:name="ring_outer">
+                    <path
+                            android:name="ring_outer_path"
+                            android:fillColor="#FF000000"
+                            android:pathData="M 0.0,-9.0 c 4.9705627482,0.0 9.0,4.0294372518 9.0,9.0 c 0.0,4.9705627482 -4.0294372518,9.0 -9.0,9.0 c -4.9705627482,0.0 -9.0,-4.0294372518 -9.0,-9.0 c 0.0,-4.9705627482 4.0294372518,-9.0 9.0,-9.0 Z"/>
+                </group>
+            </group>
+        </vector>
+    </aapt:attr>
+    <target android:name="ring_outer_path">
+        <aapt:attr name="android:animation">
+            <!-- Empty animator set -->
+            <set/>
+        </aapt:attr>
+    </target>
+</animated-vector>
diff --git a/tests/tests/graphics/res/drawable/vector_icon_group_clip.xml b/tests/tests/graphics/res/drawable/vector_icon_group_clip.xml
new file mode 100644
index 0000000..9574d7e
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/vector_icon_group_clip.xml
@@ -0,0 +1,50 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="48dp"
+        android:width="48dp"
+        android:viewportHeight="48"
+        android:viewportWidth="48">
+
+    <group>
+        <clip-path
+                android:name="clip1"
+                android:pathData="M 0, 0 l 48, 0 l 0, 30 l -48, 0 z"/>
+
+        <group>
+            <clip-path
+                    android:name="clip2"
+                    android:pathData="M 0, 18 l 48, 0 l 0, 30 l -48, 0 z"/>
+
+            <path
+                    android:name="plus1"
+                    android:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z"
+                    android:fillColor="#ff00ff00"/>
+        </group>
+
+
+        <group android:name="backgroundGroup" >
+            <path
+                    android:name="background1"
+                    android:fillColor="#80000000"
+                    android:pathData="M 0,0 l 24,0 l 0,24 l -24, 0 z" />
+            <path
+                    android:name="background2"
+                    android:fillColor="#80000000"
+                    android:pathData="M 24,24 l 24,0 l 0, 24 l -24, 0 z" />
+        </group>
+    </group>
+</vector>
diff --git a/tests/tests/graphics/res/raw/a4_portrait_rgbb.pdf b/tests/tests/graphics/res/raw/a4_portrait_rgbb.pdf
new file mode 100644
index 0000000..ed373b7
--- /dev/null
+++ b/tests/tests/graphics/res/raw/a4_portrait_rgbb.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/a5_portrait_rgbb.pdf b/tests/tests/graphics/res/raw/a5_portrait_rgbb.pdf
new file mode 100644
index 0000000..44e5a7a
--- /dev/null
+++ b/tests/tests/graphics/res/raw/a5_portrait_rgbb.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf b/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf
new file mode 100644
index 0000000..1f4ec0b
--- /dev/null
+++ b/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf b/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf
new file mode 100644
index 0000000..4d7a0f4
--- /dev/null
+++ b/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/two_pages.pdf b/tests/tests/graphics/res/raw/two_pages.pdf
new file mode 100644
index 0000000..ee73ae6
--- /dev/null
+++ b/tests/tests/graphics/res/raw/two_pages.pdf
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/cts/CameraTest.java b/tests/tests/graphics/src/android/graphics/cts/CameraTest.java
index a28d6ff..4fbe88b 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CameraTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CameraTest.java
@@ -18,8 +18,10 @@
 import android.graphics.Camera;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
+import android.support.test.filters.SmallTest;
 import android.test.AndroidTestCase;
 
+@SmallTest
 public class CameraTest extends AndroidTestCase {
     private Camera mCamera;
 
@@ -127,6 +129,35 @@
         assertEquals(1.0f, f[8]);
     }
 
+    public void testRotate() {
+        Matrix m1 = new Matrix();
+        preCompare(m1);
+
+        mCamera.rotate(15.0f, 30.0f, 45.0f);
+        Matrix m2 = new Matrix();
+        mCamera.getMatrix(m2);
+        assertFalse(m1.equals(m2));
+
+        float[] f = new float[9];
+        m2.getValues(f);
+        assertEquals(0.6123724f, f[0]);
+        assertEquals(0.6123724f, f[1]);
+        assertEquals(0.0f, f[2]);
+        assertEquals(-0.5915063f, f[3]);
+        assertEquals(0.774519f, f[4]);
+        assertEquals(0.0f, f[5]);
+        assertEquals(0.0009106233f, f[6]);
+        assertEquals(0.00027516257f, f[7]);
+        assertEquals(1.0f, f[8]);
+    }
+
+    public void testLocationAccessors() {
+        mCamera.setLocation(10.0f, 20.0f, 30.0f);
+        assertEquals(10.0f, mCamera.getLocationX());
+        assertEquals(20.0f, mCamera.getLocationY());
+        assertEquals(30.0f, mCamera.getLocationZ());
+    }
+
     public void testApplyToCanvas() {
         Canvas c1 = new Canvas();
         mCamera.applyToCanvas(c1);
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
index 760e3f9..c180906 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
@@ -16,31 +16,43 @@
 package android.graphics.cts;
 
 import android.graphics.Color;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 
-public class ColorTest extends AndroidTestCase {
+import static org.junit.Assert.*;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ColorTest {
+    @Test
     public void testAlpha(){
         assertEquals(0xff, Color.alpha(Color.RED));
         assertEquals(0xff, Color.alpha(Color.YELLOW));
         new Color();
     }
 
+    @Test
     public void testArgb(){
         assertEquals(Color.RED, Color.argb(0xff, 0xff, 0x00, 0x00));
         assertEquals(Color.YELLOW, Color.argb(0xff, 0xff, 0xff, 0x00));
     }
 
+    @Test
     public void testBlue(){
         assertEquals(0x00, Color.blue(Color.RED));
         assertEquals(0x00, Color.blue(Color.YELLOW));
     }
 
+    @Test
     public void testGreen(){
         assertEquals(0x00, Color.green(Color.RED));
         assertEquals(0xff, Color.green(Color.GREEN));
     }
 
+    @Test
     public void testHSVToColor1(){
         //abnormal case: hsv length less than 3
         try{
@@ -56,6 +68,7 @@
         assertEquals(Color.RED, Color.HSVToColor(hsv));
     }
 
+    @Test
     public void testHSVToColor2(){
         //abnormal case: hsv length less than 3
         try{
@@ -71,6 +84,7 @@
         assertEquals(Color.RED, Color.HSVToColor(0xff, hsv));
     }
 
+    @Test
     public void testParseColor(){
         //abnormal case: colorString starts with '#' but length is neither 7 nor 9
         try{
@@ -104,16 +118,19 @@
         assertEquals(Color.MAGENTA, Color.parseColor("magenta"));
     }
 
+    @Test
     public void testRed(){
         assertEquals(0xff, Color.red(Color.RED));
         assertEquals(0xff, Color.red(Color.YELLOW));
     }
 
+    @Test
     public void testRgb(){
         assertEquals(Color.RED, Color.rgb(0xff, 0x00, 0x00));
         assertEquals(Color.YELLOW, Color.rgb(0xff, 0xff, 0x00));
     }
 
+    @Test
     public void testRGBToHSV(){
         //abnormal case: hsv length less than 3
         try{
@@ -128,4 +145,14 @@
         Color.RGBToHSV(0xff, 0x00, 0x00, hsv);
         assertEquals(Color.RED, Color.HSVToColor(hsv));
     }
+
+    @Test
+    public void testLuminance() {
+        assertEquals(0, Color.luminance(Color.BLACK), 0);
+        float eps = 0.000001f;
+        assertEquals(0.0722, Color.luminance(Color.BLUE), eps);
+        assertEquals(0.2126, Color.luminance(Color.RED), eps);
+        assertEquals(0.7152, Color.luminance(Color.GREEN), eps);
+        assertEquals(1, Color.luminance(Color.WHITE), 0);
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/MatrixTest.java b/tests/tests/graphics/src/android/graphics/cts/MatrixTest.java
index 29e4f5f..5b600f6 100644
--- a/tests/tests/graphics/src/android/graphics/cts/MatrixTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/MatrixTest.java
@@ -15,39 +15,68 @@
  */
 package android.graphics.cts;
 
+import android.graphics.Camera;
 import android.graphics.Matrix;
 import android.graphics.RectF;
 import android.graphics.Matrix.ScaleToFit;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class MatrixTest extends AndroidTestCase {
+import static org.junit.Assert.*;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MatrixTest {
     private Matrix mMatrix;
     private float[] mValues;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() {
         mMatrix = new Matrix();
         mValues = new float[9];
     }
 
-    public void testConstractor() {
-        new Matrix();
-        new Matrix(mMatrix);
+    @Test
+    public void testConstructor() {
+        assertTrue(new Matrix().isIdentity());
+        assertTrue(new Matrix(mMatrix).isIdentity());
     }
 
+    @Test
     public void testIsIdentity() {
         assertTrue(mMatrix.isIdentity());
         mMatrix.setScale(0f, 0f);
         assertFalse(mMatrix.isIdentity());
     }
 
+    @Test
     public void testRectStaysRect() {
         assertTrue(mMatrix.rectStaysRect());
         mMatrix.postRotate(80);
         assertFalse(mMatrix.rectStaysRect());
     }
 
+    @Test
+    public void testIsAffine() {
+        assertTrue(mMatrix.isAffine());
+
+        // translate/scale/rotateZ don't affect whether matrix is affine
+        mMatrix.postTranslate(50, 50);
+        mMatrix.postScale(20, 4);
+        mMatrix.postRotate(80);
+        assertTrue(mMatrix.isAffine());
+
+        Camera camera = new Camera();
+        camera.setLocation(0, 0, 100);
+        camera.rotateX(20);
+        camera.getMatrix(mMatrix);
+        assertFalse(mMatrix.isAffine());
+    }
+
+    @Test
     public void testSet() {
         mValues[0] = 1000;
         mMatrix.getValues(mValues);
@@ -56,9 +85,10 @@
         mValues = new float[9];
         mValues[0] = 2000;
         matrix.getValues(mValues);
-        assertEquals(1f, mValues[0]);
+        assertEquals(1f, mValues[0], 0f);
     }
 
+    @Test
     public void testEquals() {
         mMatrix.setScale(1f, 2f);
         Matrix matrix = new Matrix();
@@ -68,6 +98,7 @@
         assertTrue(mMatrix.equals(matrix));
     }
 
+    @Test
     public void testReset() {
         mMatrix.setScale(1f, 2f, 3f, 4f);
         String expect = "[1.0, 0.0, 0.0][0.0, 2.0, -4.0][0.0, 0.0, 1.0]";
@@ -77,6 +108,7 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetScale() {
         String expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
@@ -85,6 +117,7 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetScale2() {
         String expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
@@ -94,6 +127,7 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetRotate() {
         mMatrix.setRotate(1f);
         String expect = "[0.9998477, -0.017452406, 0.0]"
@@ -101,6 +135,7 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetRotate2() {
         mMatrix.setRotate(1f, 2f, 3f);
         String expect = "[0.9998477, -0.017452406, 0.0526618]"
@@ -108,30 +143,35 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetSinCos() {
         mMatrix.setSinCos(1f, 2f);
         String expect = "[2.0, -1.0, 0.0][1.0, 2.0, 0.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetSinCos2() {
         mMatrix.setSinCos(1f, 2f, 3f, 4f);
         String expect = "[2.0, -1.0, 1.0][1.0, 2.0, -7.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetSkew() {
         mMatrix.setSkew(1f, 2f);
         String expect = "[1.0, 1.0, 0.0][2.0, 1.0, 0.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetSkew2() {
         mMatrix.setSkew(1f, 2f, 3f, 4f);
         String expect = "[1.0, 1.0, -4.0][2.0, 1.0, -6.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetConcat() {
         Matrix a = new Matrix();
         Matrix b = new Matrix();
@@ -151,24 +191,28 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPreTranslate() {
         assertTrue(mMatrix.preTranslate(1f, 2f));
         String expect = "[1.0, 0.0, 1.0][0.0, 1.0, 2.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPreScale() {
         assertTrue(mMatrix.preScale(1f, 2f));
         String expect = "[1.0, 0.0, 0.0][0.0, 2.0, 0.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPreScale2() {
         assertTrue(mMatrix.preScale(1f, 2f, 3f, 4f));
         String expect = "[1.0, 0.0, 0.0][0.0, 2.0, -4.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPreRotate() {
         assertTrue(mMatrix.preRotate(1f));
         String expect = "[0.9998477, -0.017452406, 0.0][0.017452406, 0.9998477, "
@@ -176,6 +220,7 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPreRotate2() {
         assertTrue(mMatrix.preRotate(1f, 2f, 3f));
         float[] values = new float[9];
@@ -185,18 +230,21 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPreSkew() {
         assertTrue(mMatrix.preSkew(1f, 2f));
         String expect = "[1.0, 1.0, 0.0][2.0, 1.0, 0.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPreSkew2() {
         assertTrue(mMatrix.preSkew(1f, 2f, 3f, 4f));
         String expect = "[1.0, 1.0, -4.0][2.0, 1.0, -6.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPreConcat() {
         float[] values = new float[9];
         values[0] = 1000;
@@ -207,24 +255,28 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPostTranslate() {
         assertTrue(mMatrix.postTranslate(1f, 2f));
         String expect = "[1.0, 0.0, 1.0][0.0, 1.0, 2.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPostScale() {
         assertTrue(mMatrix.postScale(1f, 2f));
         String expect = "[1.0, 0.0, 0.0][0.0, 2.0, 0.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPostScale2() {
         assertTrue(mMatrix.postScale(1f, 2f, 3f, 4f));
         String expect = "[1.0, 0.0, 0.0][0.0, 2.0, -4.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPostRotate() {
         assertTrue(mMatrix.postRotate(1f));
         String expect = "[0.9998477, -0.017452406, 0.0]" +
@@ -232,6 +284,7 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPostRotate2() {
         assertTrue(mMatrix.postRotate(1f, 2f, 3f));
         String expect = "[0.9998477, -0.017452406, 0.0526618]" +
@@ -239,18 +292,21 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPostSkew() {
         assertTrue(mMatrix.postSkew(1f, 2f));
         String expect = "[1.0, 1.0, 0.0][2.0, 1.0, 0.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPostSkew2() {
         assertTrue(mMatrix.postSkew(1f, 2f, 3f, 4f));
         String expect = "[1.0, 1.0, -4.0][2.0, 1.0, -6.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testPostConcat() {
         Matrix matrix = new Matrix();
         float[] values = new float[9];
@@ -262,6 +318,7 @@
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetRectToRect() {
         RectF r1 = new RectF();
         r1.set(1f, 2f, 3f, 3f);
@@ -292,10 +349,11 @@
         try {
             mMatrix.setRectToRect(null, null, ScaleToFit.CENTER);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testInvert() {
         Matrix matrix = new Matrix();
         float[] values = new float[9];
@@ -310,11 +368,12 @@
         try {
             result = mMatrix.invert(null);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
         assertFalse(result);
     }
 
+    @Test
     public void testSetPolyToPoly() {
         float[] src = new float[9];
         src[0] = 100f;
@@ -327,138 +386,147 @@
         try {
             mMatrix.setPolyToPoly(src, 0, dst, 0, 5);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testMapPoints() {
         float[] value = new float[9];
         value[0] = 100f;
         mMatrix.mapPoints(value);
-        assertEquals(value[0], 100f);
+        assertEquals(value[0], 100f, 0f);
         try {
             mMatrix.mapPoints(null);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testMapPoints2() {
         float[] dst = new float[9];
         dst[0] = 100f;
         float[] src = new float[9];
         src[0] = 200f;
         mMatrix.mapPoints(dst, src);
-        assertEquals(dst[0], 200f);
+        assertEquals(dst[0], 200f, 0f);
         try {
             mMatrix.mapPoints(new float[8], new float[9]);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testMapPoints3() {
         float[] dst = new float[9];
         dst[0] = 100f;
         float[] src = new float[9];
         src[0] = 200f;
         mMatrix.mapPoints(dst, 0, src, 0, 9 >> 1);
-        assertEquals(dst[0], 200f);
+        assertEquals(dst[0], 200f, 0f);
         try {
             mMatrix.mapPoints(null, 0, new float[9], 0, 1);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testMapVectors() {
         float[] values = new float[9];
-        values = new float[9];
         values[0] = 100f;
         mMatrix.mapVectors(values);
-        assertEquals(values[0], 100f);
+        assertEquals(values[0], 100f, 0f);
         try {
             mMatrix.mapVectors(null);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testMapVectors2() {
         float[] src = new float[9];
         src[0] = 100f;
         float[] dst = new float[9];
         dst[0] = 200f;
         mMatrix.mapVectors(dst, src);
-        assertEquals(dst[0], 100f);
+        assertEquals(dst[0], 100f, 0f);
 
         try {
             mMatrix.mapVectors(new float[9], new float[8]);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testMapVectors3() {
         float[] src = new float[9];
         src[0] = 100f;
         float[] dst = new float[9];
         dst[0] = 200f;
         mMatrix.mapVectors(dst, 0, src, 0, 1);
-        assertEquals(dst[0], 100f);
+        assertEquals(dst[0], 100f, 0f);
         try {
             mMatrix.mapVectors(dst, 0, src, 0, 10);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testMapRadius() {
-        assertEquals(mMatrix.mapRadius(100f), 100f);
+        assertEquals(mMatrix.mapRadius(100f), 100f, 0f);
         assertEquals(mMatrix.mapRadius(Float.MAX_VALUE),
-                Float.POSITIVE_INFINITY);
-        assertEquals(mMatrix.mapRadius(Float.MIN_VALUE), 0f);
+                Float.POSITIVE_INFINITY, 0f);
+        assertEquals(mMatrix.mapRadius(Float.MIN_VALUE), 0f, 0f);
     }
 
+    @Test
     public void testMapRect() {
         RectF r = new RectF();
         r.set(1f, 2f, 3f, 4f);
         assertTrue(mMatrix.mapRect(r));
-        assertEquals(1f, r.left);
-        assertEquals(2f, r.top);
-        assertEquals(3f, r.right);
-        assertEquals(4f, r.bottom);
+        assertEquals(1f, r.left, 0f);
+        assertEquals(2f, r.top, 0f);
+        assertEquals(3f, r.right, 0f);
+        assertEquals(4f, r.bottom, 0f);
 
         try {
             mMatrix.mapRect(null);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testMapRect2() {
         RectF dst = new RectF();
         dst.set(100f, 100f, 200f, 200f);
         RectF src = new RectF();
         dst.set(10f, 10f, 20f, 20f);
         assertTrue(mMatrix.mapRect(dst, src));
-        assertEquals(0f, dst.left);
-        assertEquals(0f, dst.top);
-        assertEquals(0f, dst.right);
-        assertEquals(0f, dst.bottom);
+        assertEquals(0f, dst.left, 0f);
+        assertEquals(0f, dst.top, 0f);
+        assertEquals(0f, dst.right, 0f);
+        assertEquals(0f, dst.bottom, 0f);
 
-        assertEquals(0f, src.left);
-        assertEquals(0f, src.top);
-        assertEquals(0f, src.right);
-        assertEquals(0f, src.bottom);
+        assertEquals(0f, src.left, 0f);
+        assertEquals(0f, src.top, 0f);
+        assertEquals(0f, src.right, 0f);
+        assertEquals(0f, src.bottom, 0f);
 
         try {
             mMatrix.mapRect(null, null);
             fail("should throw exception");
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
     }
 
+    @Test
     public void testAccessValues() {
         Matrix matrix = new Matrix();
         mMatrix.invert(matrix);
@@ -478,15 +546,18 @@
                 + values[6] + ", " + values[7] + ", " + values[8] + "]";
     }
 
+    @Test
     public void testToString() {
         assertNotNull(mMatrix.toString());
     }
 
+    @Test
     public void testToShortString() {
         String expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
         assertEquals(expect, mMatrix.toShortString());
     }
 
+    @Test
     public void testSetTranslate() {
         mMatrix.setTranslate(2f, 3f);
         String expect = "[1.0, 0.0, 2.0][0.0, 1.0, 3.0][0.0, 0.0, 1.0]";
diff --git a/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java b/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
index 8b73380..8dcd32d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
@@ -16,9 +16,6 @@
 
 package android.graphics.cts;
 
-import android.graphics.cts.R;
-
-
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -29,8 +26,10 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.support.test.filters.SmallTest;
 import android.test.AndroidTestCase;
 
+@SmallTest
 public class NinePatchTest extends AndroidTestCase {
     private static int ALPHA_OPAQUE = 0xFF;
 
@@ -57,13 +56,37 @@
     }
 
     public void testConstructor() {
-        mNinePatch = null;
+        try {
+            mNinePatch = new NinePatch(mBitmap, new byte[2]);
+            fail("should throw exception");
+        } catch (Exception e) {
+        }
+
         try {
             mNinePatch = new NinePatch(mBitmap, new byte[2], NAME);
             fail("should throw exception");
         } catch (Exception e) {
         }
+
+        mNinePatch = new NinePatch(mBitmap, mChunk);
+        assertEquals(mBitmap, mNinePatch.getBitmap());
+        assertEquals(null, mNinePatch.getName());
+
         mNinePatch = new NinePatch(mBitmap, mChunk, NAME);
+        assertEquals(mBitmap, mNinePatch.getBitmap());
+        assertEquals(NAME, mNinePatch.getName());
+    }
+
+    public void testPaintAccessors() {
+        Paint p = new Paint();
+        mNinePatch = new NinePatch(mBitmap, mChunk, NAME);
+        assertNull(mNinePatch.getPaint());
+
+        mNinePatch.setPaint(p);
+        assertEquals(p, mNinePatch.getPaint());
+
+        mNinePatch.setPaint(null);
+        assertNull(mNinePatch.getPaint());
     }
 
     public void testIsNinePatchChunk() {
@@ -71,7 +94,6 @@
         Bitmap bitmap = Bitmap.createBitmap(COLOR, 10, 10, Bitmap.Config.ARGB_4444);
         assertFalse(NinePatch.isNinePatchChunk(bitmap.getNinePatchChunk()));
         assertFalse(NinePatch.isNinePatchChunk(null));
-
     }
 
     public void testDraw() {
diff --git a/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java b/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java
index 4b01916..57a20ee 100644
--- a/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java
@@ -19,14 +19,15 @@
 import android.graphics.Outline;
 import android.graphics.Path;
 import android.graphics.Rect;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 @SmallTest
+@RunWith(AndroidJUnit4.class)
 public class OutlineTest {
     @Test
     public void testDefaults() {
@@ -40,6 +41,20 @@
     }
 
     @Test
+    public void testCopyConstructor() {
+        Outline orig = new Outline();
+        orig.setAlpha(0.5f);
+        orig.setRect(10, 10, 20, 20);
+
+        Outline copy = new Outline(orig);
+        assertEquals(0.5f, copy.getAlpha(), 0.0f);
+
+        Rect copyRect = new Rect();
+        copy.getRect(copyRect);
+        assertEquals(new Rect(10, 10, 20, 20), copyRect);
+    }
+
+    @Test
     public void testGetSetAlpha() {
         Outline outline = new Outline();
 
@@ -60,6 +75,21 @@
     }
 
     @Test
+    public void testSet() {
+        Outline orig = new Outline();
+        orig.setAlpha(0.5f);
+        orig.setRect(10, 10, 20, 20);
+
+        Outline copy = new Outline();
+        copy.set(orig);
+        assertEquals(0.5f, copy.getAlpha(), 0.0f);
+
+        Rect copyRect = new Rect();
+        copy.getRect(copyRect);
+        assertEquals(new Rect(10, 10, 20, 20), copyRect);
+    }
+
+    @Test
     public void testSetRect() {
         Outline outline = new Outline();
         Rect outRect = new Rect();
@@ -135,6 +165,11 @@
         assertTrue(outline.getRect(outRect)); // is round rect, so works
         assertTrue(outline.canClip()); // is round rect, so works
         assertFalse(outline.isEmpty());
+
+        outline.setOval(new Rect(0, 0, 50, 50)); // same x & y radii, so round rect
+        assertTrue(outline.getRect(outRect)); // is round rect, so works
+        assertTrue(outline.canClip()); // is round rect, so works
+        assertFalse(outline.isEmpty());
     }
 
     @Test
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index bc04657..c4a9223 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -1178,7 +1178,7 @@
         assertTrue(p.hasGlyph("\uD83D\uDD75"));  // SLEUTH OR SPY is introduced in Unicode 7.0
         assertTrue(p.hasGlyph("\uD83C\uDF2E"));  // TACO is introduced in Unicode 8.0
         assertTrue(p.hasGlyph("\uD83E\uDD33"));  // SELFIE is introduced in Unicode 9.0
-
+        
         // We don't require gender-neutral emoji, but if present, results must be consistent
         // whether VS is present or not.
         assertTrue(p.hasGlyph("\uD83D\uDC69\u200D\u2695") ==  // WOMAN, ZWJ, STAFF OF AESCULAPIUS
@@ -1555,4 +1555,23 @@
             }
         }
     }
+
+    public void testElegantText() {
+        final Paint p = new Paint();
+        p.setTextSize(10);
+        assertFalse(p.isElegantTextHeight());
+        final float nonElegantTop = p.getFontMetrics().top;
+        final float nonElegantBottom = p.getFontMetrics().bottom;
+
+        p.setElegantTextHeight(true);
+        assertTrue(p.isElegantTextHeight());
+        final float elegantTop = p.getFontMetrics().top;
+        final float elegantBottom = p.getFontMetrics().bottom;
+
+        assertTrue(elegantTop < nonElegantTop);
+        assertTrue(elegantBottom > nonElegantBottom);
+
+        p.setElegantTextHeight(false);
+        assertFalse(p.isElegantTextHeight());
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/PathTest.java b/tests/tests/graphics/src/android/graphics/cts/PathTest.java
index 5958a84..e7e8abb 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PathTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PathTest.java
@@ -16,8 +16,6 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
-
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -25,8 +23,16 @@
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.RectF;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class PathTest extends TestCase {
+import static org.junit.Assert.*;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PathTest {
 
     // Test constants
     private static final float LEFT = 10.0f;
@@ -36,6 +42,7 @@
     private static final float XCOORD = 40.0f;
     private static final float YCOORD = 40.0f;
 
+    @Test
     public void testConstructor() {
         // new the Path instance
         new Path();
@@ -44,9 +51,8 @@
         new Path(new Path());
     }
 
+    @Test
     public void testAddRect1() {
-
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         RectF rect = new RectF(LEFT, TOP, RIGHT, BOTTOM);
@@ -54,34 +60,34 @@
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testAddRect2() {
-
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         path.addRect(LEFT, TOP, RIGHT, BOTTOM, Path.Direction.CW);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testMoveTo() {
-        // new the Path instance
         Path path = new Path();
         path.moveTo(10.0f, 10.0f);
     }
 
+    @Test
     public void testSet() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         Path path1 = new Path();
-        setPath(path1);
+        addRectToPath(path1);
         path.set(path1);
         assertPathsAreEquivalent(path, path1);
     }
 
+    @Test
     public void testSetCleanOld() {
         Path path = new Path();
-        setPath(path);
+        addRectToPath(path);
         path.addRect(new RectF(0, 0, 10, 10), Path.Direction.CW);
         Path path1 = new Path();
         path1.addRect(new RectF(10, 10, 20, 20), Path.Direction.CW);
@@ -89,15 +95,16 @@
         assertPathsAreEquivalent(path, path1);
     }
 
+    @Test
     public void testSetEmptyPath() {
-        // new the Path instance
         Path path = new Path();
-        setPath(path);
+        addRectToPath(path);
         Path path1 = new Path();
         path.set(path1);
         assertPathsAreEquivalent(path, path1);
     }
 
+    @Test
     public void testAccessFillType() {
         // set the expected value
         Path.FillType expected1 = Path.FillType.EVEN_ODD;
@@ -118,52 +125,49 @@
         assertEquals(expected4, path.getFillType());
     }
 
+    @Test
     public void testRQuadTo() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         path.rQuadTo(5.0f, 5.0f, 10.0f, 10.0f);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testTransform1() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         Path dst = new Path();
-        setPath(path);
+        addRectToPath(path);
         path.transform(new Matrix(), dst);
         assertFalse(dst.isEmpty());
     }
 
-    public void testTransform2() {
-
-    }
-
+    @Test
     public void testLineTo() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         path.lineTo(XCOORD, YCOORD);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testClose() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
-        setPath(path);
+        addRectToPath(path);
         path.close();
     }
 
+    @Test
     public void testQuadTo() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         path.quadTo(20.0f, 20.0f, 40.0f, 40.0f);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testAddCircle() {
         // new the Path instance
         Path path = new Path();
@@ -172,8 +176,8 @@
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testArcTo1() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM);
@@ -181,8 +185,8 @@
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testArcTo2() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM);
@@ -190,81 +194,77 @@
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testComputeBounds1() {
-
         RectF expected = new RectF(0.0f, 0.0f, 0.0f, 0.0f);
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         RectF bounds = new RectF();
         path.computeBounds(bounds, true);
-        assertEquals(expected.width(), bounds.width());
-        assertEquals(expected.height(), bounds.height());
+        assertEquals(expected.width(), bounds.width(), 0.0f);
+        assertEquals(expected.height(), bounds.height(), 0.0f);
         path.computeBounds(bounds, false);
-        assertEquals(expected.width(), bounds.width());
-        assertEquals(expected.height(), bounds.height());
+        assertEquals(expected.width(), bounds.width(), 0.0f);
+        assertEquals(expected.height(), bounds.height(), 0.0f);
     }
 
+    @Test
     public void testComputeBounds2() {
-
         RectF expected = new RectF(LEFT, TOP, RIGHT, BOTTOM);
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         RectF bounds = new RectF(LEFT, TOP, RIGHT, BOTTOM);
         path.addRect(bounds, Path.Direction.CW);
         path.computeBounds(bounds, true);
-        assertEquals(expected.width(), bounds.width());
-        assertEquals(expected.height(), bounds.height());
+        assertEquals(expected.width(), bounds.width(), 0.0f);
+        assertEquals(expected.height(), bounds.height(), 0.0f);
         path.computeBounds(bounds, false);
-        assertEquals(expected.width(), bounds.width());
-        assertEquals(expected.height(), bounds.height());
+        assertEquals(expected.width(), bounds.width(), 0.0f);
+        assertEquals(expected.height(), bounds.height(), 0.0f);
     }
 
+    @Test
     public void testRMoveTo() {
-        // new the Path instance
     }
 
+    @Test
     public void testSetLastPoint() {
-        // new the Path instance
         Path path = new Path();
         path.setLastPoint(10.0f, 10.0f);
     }
 
+    @Test
     public void testRLineTo() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         path.rLineTo(10.0f, 10.0f);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testIsEmpty() {
 
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
-        setPath(path);
+        addRectToPath(path);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testRewind() {
-
-        // set the expected value
         Path.FillType expected = Path.FillType.EVEN_ODD;
 
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
-        setPath(path);
+        addRectToPath(path);
         path.rewind();
         path.setFillType(Path.FillType.EVEN_ODD);
         assertTrue(path.isEmpty());
         assertEquals(expected, path.getFillType());
     }
 
+    @Test
     public void testAddOval() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM);
@@ -272,50 +272,46 @@
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testIsRect() {
-
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
-        setPath(path);
+        addRectToPath(path);
     }
 
-    public void testIncReserve() {
-    }
-
+    @Test
     public void testAddPath1() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         Path src = new Path();
-        setPath(src);
+        addRectToPath(src);
         path.addPath(src, 10.0f, 10.0f);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testAddPath2() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         Path src = new Path();
-        setPath(src);
+        addRectToPath(src);
         path.addPath(src);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testAddPath3() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         Path src = new Path();
-        setPath(src);
+        addRectToPath(src);
         Matrix matrix = new Matrix();
         path.addPath(src, matrix);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testAddRoundRect1() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         RectF rect = new RectF(LEFT, TOP, RIGHT, BOTTOM);
@@ -323,8 +319,8 @@
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testAddRoundRect2() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         RectF rect = new RectF(LEFT, TOP, RIGHT, BOTTOM);
@@ -336,59 +332,84 @@
         assertFalse(path.isEmpty());
     }
 
-    public void testIsInverseFillType() {
+    @Test
+    public void testIsConvex1() {
+        Path path = new Path();
+        path.addRect(0, 0, 100, 10, Path.Direction.CW);
+        assertTrue(path.isConvex());
 
-        // new the Path instance
+        path.addRect(0, 0, 10, 100, Path.Direction.CW);
+        assertFalse(path.isConvex()); // path is concave
+    }
+
+    @Test
+    public void testIsConvex2() {
+        Path path = new Path();
+        path.addRect(0, 0, 40, 40, Path.Direction.CW);
+        assertTrue(path.isConvex());
+
+        path.addRect(10, 10, 30, 30, Path.Direction.CCW);
+        assertFalse(path.isConvex()); // path has hole, isn't convex
+    }
+
+    @Test
+    public void testIsConvex3() {
+        Path path = new Path();
+        path.addRect(0, 0, 10, 10, Path.Direction.CW);
+        assertTrue(path.isConvex());
+
+        path.addRect(0, 20, 10, 10, Path.Direction.CW);
+        assertFalse(path.isConvex()); // path isn't one convex shape
+    }
+
+    @Test
+    public void testIsInverseFillType() {
         Path path = new Path();
         assertFalse(path.isInverseFillType());
         path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
         assertTrue(path.isInverseFillType());
     }
 
+    @Test
     public void testOffset1() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
-        setPath(path);
+        addRectToPath(path);
         Path dst = new Path();
         path.offset(XCOORD, YCOORD, dst);
         assertFalse(dst.isEmpty());
     }
 
-    public void testOffset2() {
-        // new the Path instance
-    }
-
+    @Test
     public void testCubicTo() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         path.cubicTo(10.0f, 10.0f, 20.0f, 20.0f, 30.0f, 30.0f);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testReset() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         Path path1 = new Path();
-        setPath(path1);
+        addRectToPath(path1);
         path.set(path1);
         assertFalse(path.isEmpty());
         path.reset();
         assertTrue(path.isEmpty());
     }
 
+    @Test
     public void testToggleInverseFillType() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         path.toggleInverseFillType();
         assertTrue(path.isInverseFillType());
     }
 
+    @Test
     public void testAddArc() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM);
@@ -396,8 +417,8 @@
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testRCubicTo() {
-        // new the Path instance
         Path path = new Path();
         assertTrue(path.isEmpty());
         path.rCubicTo(10.0f, 10.0f, 11.0f, 11.0f, 12.0f, 12.0f);
@@ -441,7 +462,7 @@
         return bitmap;
     }
 
-    private void setPath(Path path) {
+    private void addRectToPath(Path path) {
         RectF rect = new RectF(LEFT, TOP, RIGHT, BOTTOM);
         path.addRect(rect, Path.Direction.CW);
     }
diff --git a/tests/tests/graphics/src/android/graphics/cts/PointFTest.java b/tests/tests/graphics/src/android/graphics/cts/PointFTest.java
index 77b72d4..0bef3e7 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PointFTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PointFTest.java
@@ -18,33 +18,21 @@
 
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
 import android.test.AndroidTestCase;
 
+@SmallTest
 public class PointFTest extends AndroidTestCase {
 
     private PointF mPointF;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mPointF = null;
-    }
-
     public void testConstructor() {
-
-        mPointF = null;
-        // new the PointF instance
         mPointF = new PointF();
-
-        mPointF = null;
-        // new the PointF instance
         mPointF = new PointF(10.0f, 10.0f);
 
-        mPointF = null;
         Point point = new Point(10, 10);
-        // new the PointF instance
         mPointF = new PointF(point);
-
     }
 
     public void testNegate() {
@@ -91,4 +79,20 @@
         assertEquals(11.1f, mPointF.y);
     }
 
+    public void testDescribeContents() {
+        mPointF = new PointF(10.0f, 20.0f);
+        assertEquals(0, mPointF.describeContents());
+    }
+
+    public void testParceling() {
+        mPointF = new PointF(10.0f, 20.0f);
+        Parcel p = Parcel.obtain();
+        mPointF.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        mPointF = new PointF();
+        mPointF.readFromParcel(p);
+        assertEquals(10.0f, mPointF.x);
+        assertEquals(20.0f, mPointF.y);
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/PointTest.java b/tests/tests/graphics/src/android/graphics/cts/PointTest.java
index e4ede58..bee4034 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PointTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PointTest.java
@@ -17,30 +17,21 @@
 package android.graphics.cts;
 
 import android.graphics.Point;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
 import android.test.AndroidTestCase;
 
+@SmallTest
 public class PointTest extends AndroidTestCase {
 
     private Point mPoint;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mPoint = null;
-    }
-
     public void testConstructor() {
-
-        // new the Point instance
         mPoint = new Point();
-
-        // new the Point instance
         mPoint = new Point(10, 10);
 
         Point point = new Point(10, 10);
-        // new the Point instance
         mPoint = new Point(point);
-
     }
 
     public void testSet() {
@@ -89,4 +80,20 @@
         assertEquals(-10, mPoint.y);
     }
 
+    public void testDescribeContents() {
+        mPoint = new Point(10, 20);
+        assertEquals(0, mPoint.describeContents());
+    }
+
+    public void testParceling() {
+        mPoint = new Point(10, 20);
+        Parcel p = Parcel.obtain();
+        mPoint.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        mPoint = new Point();
+        mPoint.readFromParcel(p);
+        assertEquals(10, mPoint.x);
+        assertEquals(20, mPoint.y);
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/RectFTest.java b/tests/tests/graphics/src/android/graphics/cts/RectFTest.java
index f5788af..0240690 100644
--- a/tests/tests/graphics/src/android/graphics/cts/RectFTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/RectFTest.java
@@ -16,46 +16,28 @@
 
 package android.graphics.cts;
 
-
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
 import android.test.AndroidTestCase;
 
+@SmallTest
 public class RectFTest extends AndroidTestCase {
-
     private RectF mRectF;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mRectF = null;
-    }
-
     public void testConstructor() {
-
-        mRectF = null;
-        // new the RectF instance
         mRectF = new RectF();
-
-        mRectF = null;
-        // new the RectF instance
         mRectF = new RectF(1.5f, 2.5f, 20.3f, 40.9f);
 
-        mRectF = null;
         RectF rectF = new RectF(1.5f, 2.5f, 20.3f, 40.9f);
-        // new the RectF instance
         mRectF = new RectF(rectF);
 
-        mRectF = null;
         Rect rect = new Rect(0, 0, 10, 10);
-        // new the RectF instance
         mRectF = new RectF(rect);
-
     }
 
     public void testSort() {
-
         mRectF = new RectF(10, 10, 5, 5);
         assertEquals(10.0f, mRectF.left);
         assertEquals(10.0f, mRectF.top);
@@ -67,22 +49,18 @@
         assertEquals(5.0f, mRectF.top);
         assertEquals(10.0f, mRectF.right);
         assertEquals(10.0f, mRectF.bottom);
-
     }
 
     public void testSet1() {
-
         mRectF = new RectF();
         mRectF.set(1.0f, 2.0f, 3.0f, 4.0f);
         assertEquals(1.0f, mRectF.left);
         assertEquals(2.0f, mRectF.top);
         assertEquals(3.0f, mRectF.right);
         assertEquals(4.0f, mRectF.bottom);
-
     }
 
     public void testSet2() {
-
         RectF rectF = new RectF(1.0f, 2.0f, 3.0f, 4.0f);
         mRectF = new RectF();
         mRectF.set(rectF);
@@ -90,11 +68,9 @@
         assertEquals(2.0f, mRectF.top);
         assertEquals(3.0f, mRectF.right);
         assertEquals(4.0f, mRectF.bottom);
-
     }
 
     public void testSet3() {
-
         Rect rect = new Rect(1, 2, 3, 4);
         mRectF = new RectF();
         mRectF.set(rect);
@@ -102,11 +78,9 @@
         assertEquals(2.0f, mRectF.top);
         assertEquals(3.0f, mRectF.right);
         assertEquals(4.0f, mRectF.bottom);
-
     }
 
     public void testIntersects1() {
-
         mRectF = new RectF(0, 0, 10, 10);
         assertTrue(mRectF.intersects(5, 5, 15, 15));
         assertEquals(0.0f, mRectF.left);
@@ -120,11 +94,9 @@
         assertEquals(0.0f, mRectF.top);
         assertEquals(10.0f, mRectF.right);
         assertEquals(10.0f, mRectF.bottom);
-
     }
 
     public void testIntersects2() {
-
         RectF rectF1;
         RectF rectF2;
 
@@ -135,11 +107,9 @@
         rectF1 = new RectF(0, 0, 10, 10);
         rectF2 = new RectF(15, 15, 25, 25);
         assertFalse(RectF.intersects(rectF1, rectF2));
-
     }
 
     public void testIntersect1() {
-
         mRectF = new RectF(0, 0, 10, 10);
         assertTrue(mRectF.intersect(5, 5, 15, 15));
         assertEquals(5.0f, mRectF.left);
@@ -153,11 +123,9 @@
         assertEquals(0.0f, mRectF.top);
         assertEquals(10.0f, mRectF.right);
         assertEquals(10.0f, mRectF.bottom);
-
     }
 
     public void testIntersect2() {
-
         RectF rectF;
 
         mRectF = new RectF(0, 0, 10, 10);
@@ -175,11 +143,9 @@
         assertEquals(0.0f, mRectF.top);
         assertEquals(10.0f, mRectF.right);
         assertEquals(10.0f, mRectF.bottom);
-
     }
 
     public void testUnion1() {
-
         // Both rect1 and rect2 are not empty.
         // 1. left < right, top < bottom
         // this.left < this.right, this.top < this.bottom
@@ -225,11 +191,9 @@
         assertEquals(0.0f, mRectF.left);
         assertEquals(1.0f, mRectF.right);
         assertEquals(1.0f, mRectF.bottom);
-
     }
 
     public void testUnion2() {
-
         RectF rectF;
 
         // Both rect1 and rect2 are not empty.
@@ -282,11 +246,9 @@
         assertEquals(0.0f, mRectF.left);
         assertEquals(1.0f, mRectF.right);
         assertEquals(1.0f, mRectF.bottom);
-
     }
 
     public void testUnion3() {
-
         // rect1 is not empty (x > right, y > bottom).
         mRectF = new RectF(0.0f, 0.0f, 1.0f, 1.0f);
         mRectF.union(2.0f, 2.0f);
@@ -318,21 +280,17 @@
         assertEquals(0.0f, mRectF.left);
         assertEquals(2.0f, mRectF.right);
         assertEquals(2.0f, mRectF.bottom);
-
     }
 
     public void testContains1() {
-
         mRectF = new RectF(1.0f, 1.0f, 20.0f, 20.0f);
         assertFalse(mRectF.contains(0.9f, 0.9f));
         assertTrue(mRectF.contains(1.0f, 1.0f));
         assertTrue(mRectF.contains(19.9f, 19.9f));
         assertFalse(mRectF.contains(20.0f, 20.0f));
-
     }
 
     public void testContains2() {
-
         mRectF = new RectF(1.0f, 1.0f, 20.0f, 20.0f);
         assertTrue(mRectF.contains(1.0f, 1.0f, 20.0f, 20.0f));
         assertTrue(mRectF.contains(2.0f, 2.0f, 19.0f, 19.0f));
@@ -341,7 +299,6 @@
     }
 
     public void testContains3() {
-
         RectF rectF;
         mRectF = new RectF(1.0f, 1.0f, 20.0f, 20.0f);
         rectF = new RectF(1.0f, 1.0f, 20.0f, 20.0f);
@@ -352,22 +309,18 @@
         assertFalse(mRectF.contains(rectF));
         rectF = new RectF(0.0f, 0.0f, 19.0f, 19.0f);
         assertFalse(mRectF.contains(rectF));
-
     }
 
     public void testOffset() {
-
        mRectF = new RectF(5, 5, 10, 10);
        mRectF.offset(1.0f, 1.0f);
        assertEquals(6.0f, mRectF.left);
        assertEquals(6.0f, mRectF.top);
        assertEquals(11.0f, mRectF.right);
        assertEquals(11.0f, mRectF.bottom);
-
     }
 
     public void testInset() {
-
         mRectF = new RectF(5.0f, 5.0f, 10.0f, 10.0f);
         mRectF.inset(1.0f, 1.0f);
         assertEquals(6.0f, mRectF.left);
@@ -381,7 +334,6 @@
         assertEquals(4.0f, mRectF.top);
         assertEquals(11.0f, mRectF.right);
         assertEquals(11.0f, mRectF.bottom);
-
     }
 
     public void testHeight() {
@@ -395,18 +347,15 @@
     }
 
     public void testOffsetTo() {
-
         mRectF = new RectF(5, 5, 10, 10);
         mRectF.offsetTo(1.0f, 1.0f);
         assertEquals(1.0f, mRectF.left);
         assertEquals(1.0f, mRectF.top);
         assertEquals(6.0f, mRectF.right);
         assertEquals(6.0f, mRectF.bottom);
-
     }
 
     public void testSetEmpty() {
-
         // Before setEmpty()
         mRectF = new RectF(1, 2, 3, 4);
         assertEquals(1.0f, mRectF.left);
@@ -420,11 +369,9 @@
         assertEquals(0.0f, mRectF.top);
         assertEquals(0.0f, mRectF.right);
         assertEquals(0.0f, mRectF.bottom);
-
     }
 
     public void testIsEmpty() {
-
         mRectF = new RectF();
         assertTrue(mRectF.isEmpty());
         mRectF = new RectF(1.0f, 1.0f, 1.0f, 1.0f);
@@ -433,22 +380,18 @@
         assertTrue(mRectF.isEmpty());
         mRectF = new RectF(1.0f, 1.0f, 20.0f, 20.0f);
         assertFalse(mRectF.isEmpty());
-
     }
 
     public void testCenterX() {
-
         mRectF = new RectF(10.0f, 10.0f, 20.0f, 20.0f);
         assertEquals(15.0f, mRectF.centerX());
         mRectF = new RectF(10.5f, 10.0f, 20.0f, 20.0f);
         assertEquals(15.25f, mRectF.centerX());
         mRectF = new RectF(10.4f, 10.0f, 20.0f, 20.0f);
         assertEquals(15.2f, mRectF.centerX());
-
     }
 
     public void testCenterY() {
-
         mRectF = new RectF(10.0f, 10.0f, 20.0f, 20.0f);
         assertEquals(15.0f, mRectF.centerY());
         mRectF = new RectF(10.0f, 10.5f, 20.0f, 20.0f);
@@ -458,12 +401,16 @@
     }
 
     public void testToString() {
-        mRectF = new RectF();
-        assertNotNull(mRectF.toString());
+        mRectF = new RectF(10.0f, 20.0f, 30.0f, 40.0f);
+        assertEquals("RectF(10.0, 20.0, 30.0, 40.0)", mRectF.toString());
+    }
+
+    public void testToShortString() {
+        mRectF = new RectF(10.0f, 20.0f, 30.0f, 40.0f);
+        assertEquals("[10.0,20.0][30.0,40.0]", mRectF.toShortString());
     }
 
     public void testSetIntersect() {
-
         RectF rectF1 = new RectF(0, 0, 10, 10);
         RectF rectF2 = new RectF(5, 5, 15, 15);
 
@@ -482,11 +429,9 @@
         assertEquals(5.0f, mRectF.top);
         assertEquals(10.0f, mRectF.right);
         assertEquals(10.0f, mRectF.bottom);
-
     }
 
     public void testRoundOut() {
-
         Rect rect = new Rect();
         mRectF = new RectF(1.2f, 1.8f, 5.2f, 5.8f);
         mRectF.roundOut(rect);
@@ -494,11 +439,9 @@
         assertEquals(1, rect.top);
         assertEquals(6, rect.right);
         assertEquals(6, rect.bottom);
-
     }
 
     public void testRound() {
-
         Rect rect = new Rect();
         mRectF = new RectF(1.2f, 1.8f, 5.2f, 5.8f);
         mRectF.round(rect);
@@ -506,7 +449,6 @@
         assertEquals(2, rect.top);
         assertEquals(5, rect.right);
         assertEquals(6, rect.bottom);
-
     }
 
     public void testWriteReadParcel() {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/Animatable2_AnimationCallbackTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/Animatable2_AnimationCallbackTest.java
new file mode 100644
index 0000000..deb0e87
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/Animatable2_AnimationCallbackTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.graphics.drawable.cts;
+
+import junit.framework.TestCase;
+
+import android.graphics.drawable.Animatable2.AnimationCallback;
+import android.support.test.filters.SmallTest;
+
+@SmallTest
+public class Animatable2_AnimationCallbackTest extends TestCase {
+
+    public void testCallback() {
+        // These are no-op methods. Just make sure they don't crash.
+        AnimationCallback callback = new AnimationCallback() {};
+        callback.onAnimationStart(null);
+        callback.onAnimationEnd(null);
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
index 5dabdfd..7ab3d35 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
@@ -50,11 +50,12 @@
 
     private static final int IMAGE_WIDTH = 64;
     private static final int IMAGE_HEIGHT = 64;
+    private static final long MAX_TIMEOUT_MS = 1000;
+    private static final long MAX_START_TIMEOUT_MS = 5000;
+    private static final int MS_TO_NS = 1000000;
 
     private DrawableStubActivity mActivity;
     private Resources mResources;
-    private Bitmap mBitmap;
-    private Canvas mCanvas;
     private static final boolean DBG_DUMP_PNG = false;
     private final int mResId = R.drawable.animation_vector_drawable_grouping_1;
     private final int mLayoutId = R.layout.animated_vector_drawable_source;
@@ -69,9 +70,6 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        mBitmap = Bitmap.createBitmap(IMAGE_WIDTH, IMAGE_HEIGHT, Bitmap.Config.ARGB_8888);
-        mCanvas = new Canvas(mBitmap);
-
         mActivity = getActivity();
         mResources = mActivity.getResources();
     }
@@ -123,23 +121,26 @@
         if (type != XmlPullParser.START_TAG) {
             throw new XmlPullParserException("No start tag found");
         }
+        Bitmap bitmap = Bitmap.createBitmap(IMAGE_WIDTH, IMAGE_HEIGHT, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
         AnimatedVectorDrawable drawable = new AnimatedVectorDrawable();
         drawable.inflate(mResources, parser, attrs);
         drawable.setBounds(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
-        mBitmap.eraseColor(0);
-        drawable.draw(mCanvas);
-        int sunColor = mBitmap.getPixel(IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2);
-        int earthColor = mBitmap.getPixel(IMAGE_WIDTH * 3 / 4 + 2, IMAGE_HEIGHT / 2);
+        bitmap.eraseColor(0);
+        drawable.draw(canvas);
+        int sunColor = bitmap.getPixel(IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2);
+        int earthColor = bitmap.getPixel(IMAGE_WIDTH * 3 / 4 + 2, IMAGE_HEIGHT / 2);
         assertTrue(sunColor == 0xFFFF8000);
         assertTrue(earthColor == 0xFF5656EA);
 
         if (DBG_DUMP_PNG) {
-            saveVectorDrawableIntoPNG(mBitmap, mResId);
+            saveVectorDrawableIntoPNG(bitmap, mResId);
         }
     }
 
     @MediumTest
-    public void testSingleFrameAnimation() throws Exception {
+    public void testSingleFrameAnimation() {
+        final MyCallback callback = new MyCallback();
         int resId = R.drawable.avd_single_frame;
         final AnimatedVectorDrawable d1 =
                 (AnimatedVectorDrawable) mResources.getDrawable(resId);
@@ -147,25 +148,47 @@
         mActivity.runOnUiThread(new Runnable() {
             @Override
             public void run() {
+                Bitmap bitmap =
+                        Bitmap.createBitmap(IMAGE_WIDTH, IMAGE_HEIGHT, Bitmap.Config.ARGB_8888);
+                Canvas canvas = new Canvas(bitmap);
+
                 mActivity.setContentView(mLayoutId);
                 ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
                 imageView.setImageDrawable(d1);
                 d1.start();
                 d1.stop();
                 d1.setBounds(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
-                mBitmap.eraseColor(0);
-                d1.draw(mCanvas);
+                bitmap.eraseColor(0);
+                d1.draw(canvas);
+                int endColor = bitmap.getPixel(IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2);
+                assertEquals("Center point's color must be green", 0xFF00FF00, endColor);
             }
         });
+    }
 
-        getInstrumentation().waitForIdleSync();
-        int endColor = mBitmap.getPixel(IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2);
-
-        if (DBG_DUMP_PNG) {
-            saveVectorDrawableIntoPNG(mBitmap, resId);
-        }
-
-        assertEquals("Center point's color must be green", 0xFF00FF00, endColor);
+    @SmallTest
+    public void testEmptyAnimatorSet() throws InterruptedException {
+        int resId = R.drawable.avd_empty_animator;
+        final MyCallback callback = new MyCallback();
+        final AnimatedVectorDrawable d1 =
+                (AnimatedVectorDrawable) mResources.getDrawable(resId);
+        d1.registerAnimationCallback(callback);
+        mActivity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.setContentView(mLayoutId);
+                ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+                imageView.setImageDrawable(d1);
+                d1.registerAnimationCallback(callback);
+                d1.start();
+                callback.notifyStarted();
+            }
+        });
+        callback.waitForStart();
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
+        // Check that the AVD with empty AnimatorSet has finished
+        callback.assertEnded(true);
+        callback.assertAVDRuntime(0, 64 * MS_TO_NS); // 4 frames
     }
 
     @SmallTest
@@ -252,33 +275,36 @@
 
     @MediumTest
     public void testReset() {
+        final MyCallback callback = new MyCallback();
         final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
         // The AVD has a duration as 100ms.
         mActivity.runOnUiThread(new Runnable() {
             @Override
             public void run() {
+                d1.registerAnimationCallback(callback);
                 d1.start();
                 d1.reset();
             }
         });
-        getInstrumentation().waitForIdleSync();
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
         assertFalse(d1.isRunning());
 
     }
 
     @MediumTest
     public void testStop() {
+        final MyCallback callback = new MyCallback();
         final AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
         // The AVD has a duration as 100ms.
         mActivity.runOnUiThread(new Runnable() {
             @Override
             public void run() {
+                d1.registerAnimationCallback(callback);
                 d1.start();
                 d1.stop();
-
             }
         });
-        getInstrumentation().waitForIdleSync();
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
         assertFalse(d1.isRunning());
     }
 
@@ -294,12 +320,13 @@
                 AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
                 d1.registerAnimationCallback(callback);
                 d1.start();
+                callback.notifyStarted();
             }
         });
-        getInstrumentation().waitForIdleSync();
-        sleep(200);
-        assertTrue(callback.mStart);
-        assertTrue(callback.mEnd);
+        callback.waitForStart();
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
+        callback.assertStarted(true);
+        callback.assertEnded(true);
     }
 
     @MediumTest
@@ -317,12 +344,14 @@
                 d1.reset();
                 d1.registerAnimationCallback(callback);
                 d1.start();
+                callback.notifyStarted();
             }
         });
-        getInstrumentation().waitForIdleSync();
-        sleep(200);
-        assertTrue(callback.mStart);
-        assertTrue(callback.mEnd);
+        callback.waitForStart();
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
+
+        callback.assertStarted(true);
+        callback.assertEnded(true);
     }
 
     @MediumTest
@@ -337,17 +366,20 @@
                 AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
                 d1.start();
                 d1.registerAnimationCallback(callback);
+                callback.notifyStarted();
             }
         });
-        getInstrumentation().waitForIdleSync();
-        sleep(200);
+        callback.waitForStart();
+
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
         // Whether or not the callback.start is true could vary when running on Render Thread.
-        // Therefore, we don't make assertion here. The most useful flag is the callback.mEnd.
-        assertTrue(callback.mEnd);
+        // Therefore, we don't make assertion here. The most useful flag is the callback.mEnded.
+        callback.assertEnded(true);
+        callback.assertAVDRuntime(0, 400 * MS_TO_NS); // 4 times of the duration of the AVD.
     }
 
     @MediumTest
-    public void testRemoveCallback() {
+    public void testRemoveCallback() throws InterruptedException {
         final MyCallback callback = new MyCallback();
         // The AVD has a duration as 100ms.
         mActivity.runOnUiThread(new Runnable() {
@@ -359,16 +391,18 @@
                 d1.registerAnimationCallback(callback);
                 assertTrue(d1.unregisterAnimationCallback(callback));
                 d1.start();
+                callback.notifyStarted();
             }
         });
-        getInstrumentation().waitForIdleSync();
+        callback.waitForStart();
 
-        assertFalse(callback.mStart);
-        assertFalse(callback.mEnd);
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
+        callback.assertStarted(false);
+        callback.assertEnded(false);
     }
 
     @MediumTest
-    public void testClearCallback() {
+    public void testClearCallback() throws InterruptedException {
         final MyCallback callback = new MyCallback();
 
         // The AVD has a duration as 100ms.
@@ -381,27 +415,91 @@
                 d1.registerAnimationCallback(callback);
                 d1.clearAnimationCallbacks();
                 d1.start();
+                callback.notifyStarted();
             }
         });
+        callback.waitForStart();
 
-        getInstrumentation().waitForIdleSync();
-
-        assertFalse(callback.mStart);
-        assertFalse(callback.mEnd);
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
+        callback.assertStarted(false);
+        callback.assertEnded(false);
     }
 
+    // The time out is expected when the listener is removed successfully.
+    // Such that we don't get the end event.
+    private void waitForAVDStop(MyCallback callback, long timeout) {
+        try {
+            callback.waitForEnd(timeout);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+            fail("We should not see the AVD run this long time!");
+        }
+    }
+
+    // Now this class can not only listen to the events, but also synchronize the key events,
+    // logging the event timestamp, and centralize some assertions.
     class MyCallback extends Animatable2.AnimationCallback {
-        boolean mStart = false;
-        boolean mEnd = false;
+        private boolean mStarted = false;
+        private boolean mEnded = false;
+
+        private long mStartNs = Long.MAX_VALUE;
+        private long mEndNs = Long.MIN_VALUE;
+
+        // Use this lock to make sure the onAnimationEnd() has been called.
+        // Each sub test should have its own lock.
+        private final Object mEndLock = new Object();
+
+        // Use this lock to make sure the test thread know when the AVD.start() has been called.
+        // Each sub test should have its own lock.
+        private final Object mStartLock = new Object();
+
+        public void waitForEnd(long timeoutMs) throws InterruptedException {
+            synchronized (mEndLock) {
+                mEndLock.wait(timeoutMs);
+            }
+        }
+
+        public void waitForStart() throws InterruptedException {
+            synchronized(mStartLock) {
+                mStartLock.wait(MAX_START_TIMEOUT_MS);
+            }
+        }
+
+        public void notifyStarted() {
+            mStartNs = System.nanoTime();
+            synchronized(mStartLock) {
+                mStartLock.notify();
+            }
+        }
 
         @Override
         public void onAnimationStart(Drawable drawable) {
-            mStart = true;
+            mStarted = true;
         }
 
         @Override
         public void onAnimationEnd(Drawable drawable) {
-            mEnd = true;
+            mEndNs = System.nanoTime();
+            mEnded = true;
+            synchronized (mEndLock) {
+                mEndLock.notify();
+            }
+        }
+
+        public void assertStarted(boolean started) {
+            assertEquals(started, mStarted);
+        }
+
+        public void assertEnded(boolean ended) {
+            assertEquals(ended, mEnded);
+        }
+
+        public void assertAVDRuntime(long min, long max) {
+            assertTrue(mStartNs != Long.MAX_VALUE);
+            assertTrue(mEndNs != Long.MIN_VALUE);
+            long durationNs = mEndNs - mStartNs;
+            assertTrue("current duration " + durationNs + " should be within " +
+                    min + "," + max, durationNs <= max && durationNs >= min);
         }
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerStateTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerStateTest.java
index 8cbecab..726466c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerStateTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerStateTest.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable.cts;
 
+import junit.framework.TestCase;
 
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
@@ -23,12 +24,12 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.DrawableContainer;
-import android.graphics.drawable.LevelListDrawable;
 import android.graphics.drawable.DrawableContainer.DrawableContainerState;
+import android.graphics.drawable.LevelListDrawable;
+import android.support.test.filters.SmallTest;
 
-import junit.framework.TestCase;
-
-public class DrawableContainerStateTest extends TestCase{
+@SmallTest
+public class DrawableContainerStateTest extends TestCase {
     private DrawableContainerState mDrawableContainerState;
 
     private DrawableContainer mDrawableContainer;
@@ -36,6 +37,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
         // DrawableContainerState has no public constructor. Obtain an instance through
         // LevelListDrawable.getConstants(). This is fine for testing the final methods of
         // DrawableContainerState.
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java
index bc452f3..81d9386 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java
@@ -16,14 +16,30 @@
 
 package android.graphics.drawable.cts;
 
-import android.content.res.Resources.Theme;
-import android.graphics.drawable.Drawable.Callback;
-import android.view.View;
-import android.graphics.cts.R;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.content.ContentResolver;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.cts.R;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Drawable.Callback;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+import android.util.AttributeSet;
+import android.util.StateSet;
+import android.util.TypedValue;
+import android.util.Xml;
+import android.view.View;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -32,24 +48,11 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
-import android.content.ContentResolver;
-import android.content.res.Resources;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
-import android.util.StateSet;
-import android.util.TypedValue;
-import android.util.Xml;
-
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
+@SmallTest
 public class DrawableTest extends AndroidTestCase {
     Resources mResources;
 
@@ -546,13 +549,22 @@
     }
 
     public void testScheduleSelf() {
-        MockDrawable mockDrawable = new MockDrawable();
-        MockCallback mockCallback = new MockCallback();
-        mockDrawable.setCallback(mockCallback);
+        Drawable mockDrawable = new MockDrawable();
         mockDrawable.scheduleSelf(null, 1000L);
-        assertEquals(mockDrawable, mockCallback.getScheduleDrawable());
-        assertNull(mockCallback.getRunnable());
-        assertEquals(1000L, mockCallback.getWhen());
+
+        Runnable runnable = mock(Runnable.class);
+        mockDrawable.scheduleSelf(runnable, 1000L);
+
+        Callback mockCallback = mock(Callback.class);
+        mockDrawable.setCallback(mockCallback);
+        mockDrawable.scheduleSelf(runnable, 1000L);
+        verify(mockCallback).scheduleDrawable(eq(mockDrawable), eq(runnable), eq(1000L));
+
+        mockDrawable.scheduleSelf(runnable, 0L);
+        verify(mockCallback).scheduleDrawable(eq(mockDrawable), eq(runnable), eq(0L));
+
+        mockDrawable.scheduleSelf(runnable, -1000L);
+        verify(mockCallback).scheduleDrawable(eq(mockDrawable), eq(runnable), eq(-1000L));
     }
 
     public void testAccessCallback() {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
index 713f61a..b062073 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -16,9 +16,13 @@
 
 package android.graphics.drawable.cts;
 
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.app.Activity;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -28,11 +32,14 @@
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.cts.MockActivity;
 import android.graphics.cts.R;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.GradientDrawable.Orientation;
-import android.test.AndroidTestCase;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
@@ -42,9 +49,21 @@
 import java.util.Arrays;
 
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-public class GradientDrawableTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class GradientDrawableTest {
+
+    @Rule
+    public ActivityTestRule<MockActivity> mActivityRule
+            = new ActivityTestRule<>(MockActivity.class);
+
     @SmallTest
+    @Test
     public void testConstructor() {
         int[] color = new int[] {1, 2, 3};
 
@@ -54,6 +73,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetOpacity() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         assertEquals("Default opacity is TRANSLUCENT",
@@ -87,6 +107,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetOrientation() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         Orientation orientation;
@@ -98,6 +119,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetCornerRadii() {
         float[] radii = new float[] {1.0f, 2.0f, 3.0f};
 
@@ -116,6 +138,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetCornerRadius() {
         GradientDrawable gradientDrawable = new GradientDrawable();
 
@@ -124,6 +147,22 @@
     }
 
     @SmallTest
+    @Test
+    public void testGetCornerRadius() {
+        GradientDrawable gradientDrawable = new GradientDrawable();
+        gradientDrawable.setCornerRadius(5.5f);
+        assertEquals(gradientDrawable.getCornerRadius(), 5.5f, 0);
+        float[] radii = new float[] {1.0f, 2.0f, 3.0f};
+        gradientDrawable.setCornerRadii(radii);
+        assertEquals(5.5f, gradientDrawable.getCornerRadius(), 0);
+        gradientDrawable.setShape(GradientDrawable.OVAL);
+        assertEquals(5.5f, gradientDrawable.getCornerRadius(), 0);
+        gradientDrawable.setCornerRadii(null);
+        assertEquals(0, gradientDrawable.getCornerRadius(), 0);
+    }
+
+    @SmallTest
+    @Test
     public void testSetStroke() {
         helpTestSetStroke(2, Color.RED);
         helpTestSetStroke(-2, Color.TRANSPARENT);
@@ -137,6 +176,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetStroke_WidthGap() {
         helpTestSetStroke_WidthGap(2, Color.RED, 3.4f, 5.5f);
         helpTestSetStroke_WidthGap(-2, Color.TRANSPARENT, -3.4f, -5.5f);
@@ -151,6 +191,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetStrokeList() {
         helpTestSetStrokeList(2, ColorStateList.valueOf(Color.RED));
         helpTestSetStrokeList(-2, ColorStateList.valueOf(Color.TRANSPARENT));
@@ -165,6 +206,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetStrokeList_WidthGap() {
         helpTestSetStrokeList_WidthGap(2, ColorStateList.valueOf(Color.RED), 3.4f, 5.5f);
         helpTestSetStrokeList_WidthGap(-2, ColorStateList.valueOf(Color.TRANSPARENT), -3.4f, -5.5f);
@@ -179,6 +221,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetSize() {
         helpTestSetSize(6, 4);
         helpTestSetSize(-30, -40);
@@ -194,6 +237,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetShape() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         int shape;
@@ -210,6 +254,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetGradientType() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         int gradientType;
@@ -226,6 +271,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetGradientCenter() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         float centerX;
@@ -245,11 +291,12 @@
         centerX = 0.0f;
         centerY = 0.0f;
         gradientDrawable.setGradientCenter(centerX, centerY);
-        assertEquals(centerX, gradientDrawable.getGradientCenterX());
-        assertEquals(centerY, gradientDrawable.getGradientCenterY());
+        assertEquals(centerX, gradientDrawable.getGradientCenterX(), 0.01f);
+        assertEquals(centerY, gradientDrawable.getGradientCenterY(), 0.01f);
     }
 
     @SmallTest
+    @Test
     public void testSetGradientRadius() {
         GradientDrawable gradientDrawable = new GradientDrawable();
 
@@ -258,6 +305,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetUseLevel() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         boolean useLevel;
@@ -276,6 +324,7 @@
     }
 
     @SmallTest
+    @Test
     public void testDraw() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         Canvas c = new Canvas();
@@ -286,6 +335,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetColor() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         int color;
@@ -302,6 +352,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetColors() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         int[] colors;
@@ -318,6 +369,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetColorList() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         ColorStateList color;
@@ -332,6 +384,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetChangingConfigurations() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         assertEquals(0, gradientDrawable.getChangingConfigurations());
@@ -344,6 +397,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetAlpha() {
         GradientDrawable gradientDrawable = new GradientDrawable();
 
@@ -352,6 +406,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetDither() {
         GradientDrawable gradientDrawable = new GradientDrawable();
 
@@ -360,6 +415,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetColorFilter() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         ColorFilter cf = new ColorFilter();
@@ -370,6 +426,7 @@
     }
 
     @SmallTest
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         GradientDrawable gradientDrawable = new GradientDrawable();
         Rect rect = new Rect();
@@ -379,7 +436,7 @@
         assertEquals(0, rect.right);
         assertEquals(0, rect.bottom);
 
-        Resources resources = mContext.getResources();
+        Resources resources = mActivityRule.getActivity().getResources();
         XmlPullParser parser = resources.getXml(R.drawable.gradientdrawable);
         AttributeSet attrs = Xml.asAttributeSet(parser);
 
@@ -415,9 +472,10 @@
     }
 
     @SmallTest
+    @Test
     public void testInflateGradientRadius() throws XmlPullParserException, IOException {
         Rect parentBounds = new Rect(0, 0, 100, 100);
-        Resources resources = mContext.getResources();
+        Resources resources = mActivityRule.getActivity().getResources();
 
         GradientDrawable gradientDrawable;
         float radius;
@@ -436,6 +494,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetIntrinsicWidth() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         gradientDrawable.setSize(6, 4);
@@ -446,6 +505,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetIntrinsicHeight() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         gradientDrawable.setSize(5, 3);
@@ -456,14 +516,16 @@
     }
 
     @SmallTest
+    @Test
     public void testGetConstantState() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         assertNotNull(gradientDrawable.getConstantState());
     }
 
     @SmallTest
+    @Test
     public void testMutate() {
-        Resources resources = mContext.getResources();
+        Resources resources = mActivityRule.getActivity().getResources();
         GradientDrawable d1 = (GradientDrawable) resources.getDrawable(R.drawable.gradientdrawable);
         GradientDrawable d2 = (GradientDrawable) resources.getDrawable(R.drawable.gradientdrawable);
         GradientDrawable d3 = (GradientDrawable) resources.getDrawable(R.drawable.gradientdrawable);
@@ -495,8 +557,9 @@
     }
 
     @MediumTest
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
-        final Resources res = getContext().getResources();
+        final Resources res = mActivityRule.getActivity().getResources();
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
             testPreloadDensityInner(res, densityDpi);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawable_ShaderFactoryTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawable_ShaderFactoryTest.java
index b736519..0447fb2 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawable_ShaderFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawable_ShaderFactoryTest.java
@@ -17,10 +17,26 @@
 package android.graphics.drawable.cts;
 
 import junit.framework.TestCase;
-import android.graphics.drawable.ShapeDrawable;
 
+import android.graphics.Shader;
+import android.graphics.drawable.ShapeDrawable.ShaderFactory;
+import android.support.test.filters.SmallTest;
+
+@SmallTest
 public class ShapeDrawable_ShaderFactoryTest extends TestCase {
+
     public void testResize() {
-        // resize is an abstract function.
+        // This is an abstract function, but coverage
+        // complains if we don't call it.
+        ShaderFactory impl = new ShaderFactoryImpl();
+        assertNull(impl.resize(0, 0));
+    }
+
+    private class ShaderFactoryImpl extends ShaderFactory {
+
+        @Override
+        public Shader resize(int width, int height) {
+            return null;
+        }
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
index e2fe8c5..005fe52 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
@@ -93,6 +93,7 @@
             R.drawable.vector_icon_stroke_3,
             R.drawable.vector_icon_scale_1,
             R.drawable.vector_icon_scale_2,
+            R.drawable.vector_icon_group_clip,
     };
 
     private static final int[] L_M_GOLDEN_IMAGES = new int[] {
@@ -109,6 +110,7 @@
             R.drawable.vector_icon_stroke_3_golden,
             R.drawable.vector_icon_scale_1_golden,
             R.drawable.vector_icon_scale_2_golden,
+            R.drawable.vector_icon_group_clip_golden,
     };
 
     private static final int[] N_ICON_RES_IDS = new int[] {
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfDocumentTest.java b/tests/tests/graphics/src/android/graphics/pdf/cts/PdfDocumentTest.java
new file mode 100644
index 0000000..09c6cd0
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/pdf/cts/PdfDocumentTest.java
@@ -0,0 +1,424 @@
+/*
+ * 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.graphics.pdf.cts;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.pdf.PdfDocument;
+import android.graphics.pdf.PdfRenderer;
+import android.os.ParcelFileDescriptor;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+import static android.graphics.pdf.cts.Utils.assertException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests {@link PdfDocument}
+ */
+@RunWith(AndroidJUnit4.class)
+public class PdfDocumentTest {
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    @Test
+    public void getPagesEmptyDocAfterClose() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        doc.close();
+        assertEquals(0, doc.getPages().size());
+    }
+
+    @Test
+    public void closeClosedDoc() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        doc.close();
+
+        // legacy behavior, double close does nothing
+        doc.close();
+    }
+
+    @Test
+    public void writeClosedDoc() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        doc.close();
+
+        OutputStream os = new FileOutputStream(File.createTempFile("tmp", "pdf",
+                mContext.getCacheDir()));
+
+        assertException(() -> doc.writeTo(os), IllegalStateException.class);
+    }
+
+    @Test
+    public void startPageClosedDoc() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        doc.close();
+
+        assertException(() -> doc.startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create()),
+                IllegalStateException.class);
+    }
+
+    @Test
+    public void finishPageTwiceDoc() throws Exception {
+        PdfDocument doc = new PdfDocument();
+
+        PdfDocument.Page page = doc
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        doc.finishPage(page);
+        assertException(() -> doc.finishPage(page), IllegalStateException.class);
+
+        doc.close();
+    }
+
+    @Test
+    public void closeWithOpenPage() throws Exception {
+        PdfDocument doc = new PdfDocument();
+
+        PdfDocument.Page page = doc
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        assertException(doc::close, IllegalStateException.class);
+        doc.finishPage(page);
+        doc.close();
+    }
+
+    @Test
+    public void writeEmptyDoc() throws Exception {
+        PdfDocument doc = new PdfDocument();
+
+        // Legacy behavior. Writing an empty doc does not fail.
+        File pdfFile = File.createTempFile("tmp", "pdf", mContext.getCacheDir());
+        try (OutputStream os = new FileOutputStream(pdfFile)) {
+            doc.writeTo(os);
+        }
+        doc.close();
+    }
+
+    @Test
+    public void writeWithOpenPage() throws Exception {
+        PdfDocument doc = new PdfDocument();
+
+        PdfDocument.Page page = doc
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+
+        File pdfFile = File.createTempFile("tmp", "pdf", mContext.getCacheDir());
+        try (OutputStream os = new FileOutputStream(pdfFile)) {
+            assertException(() -> doc.writeTo(os), IllegalStateException.class);
+        }
+
+        doc.finishPage(page);
+        doc.close();
+    }
+
+    @Test
+    public void openTwoPages() throws Exception {
+        PdfDocument doc = new PdfDocument();
+
+        PdfDocument.Page page = doc
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        assertException(() -> doc.startPage(new PdfDocument.PageInfo.Builder(100, 100, 1).create()),
+                IllegalStateException.class);
+
+        doc.finishPage(page);
+        doc.close();
+    }
+
+    @Test
+    public void finishPageFromWrongDoc() throws Exception {
+        PdfDocument doc1 = new PdfDocument();
+        PdfDocument doc2 = new PdfDocument();
+
+        PdfDocument.Page page1 = doc1
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        assertException(() -> doc2.finishPage(page1), IllegalStateException.class);
+
+        PdfDocument.Page page2 = doc2
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        assertException(() -> doc1.finishPage(page2), IllegalStateException.class);
+
+        doc1.finishPage(page1);
+        doc2.finishPage(page2);
+        doc1.close();
+        doc2.close();
+    }
+
+    @Test
+    public void writeTwoPageDocWithSameIndex() throws Exception {
+        PdfDocument doc = new PdfDocument();
+
+        PdfDocument.Page page0 = doc
+                .startPage(new PdfDocument.PageInfo.Builder(101, 100, 0).create());
+        doc.finishPage(page0);
+        PdfDocument.Page page1 = doc
+                .startPage(new PdfDocument.PageInfo.Builder(201, 200, 0).create());
+        doc.finishPage(page1);
+        assertEquals(2, doc.getPages().size());
+
+        File pdfFile = File.createTempFile("tmp", "pdf", mContext.getCacheDir());
+        try (OutputStream os = new FileOutputStream(pdfFile)) {
+            doc.writeTo(os);
+        }
+
+        try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(pdfFile,
+                ParcelFileDescriptor.MODE_READ_ONLY)) {
+            PdfRenderer renderer = new PdfRenderer(fd);
+            assertEquals(2, renderer.getPageCount());
+            try (PdfRenderer.Page page = renderer.openPage(0)) {
+                assertEquals(0, page.getIndex());
+                assertEquals(101, page.getWidth());
+                assertEquals(100, page.getHeight());
+            }
+            try (PdfRenderer.Page page = renderer.openPage(1)) {
+                assertEquals(1, page.getIndex());
+                assertEquals(201, page.getWidth());
+                assertEquals(200, page.getHeight());
+            }
+        }
+
+        doc.close();
+    }
+
+    /**
+     * Replacement for non existing <code>{@link PdfDocument.PageInfo}#equals()</code>
+     *
+     * @param a The first info, can not be null
+     * @param b The second info, can not be null
+     *
+     * @return If a is equal to b
+     */
+    private boolean pageInfoEquals(@NonNull PdfDocument.PageInfo a,
+            @NonNull PdfDocument.PageInfo b) {
+        return a.getContentRect().equals(b.getContentRect()) &&
+                a.getPageHeight() == b.getPageHeight() && a.getPageWidth() == b.getPageWidth() &&
+                a.getPageNumber() == b.getPageNumber();
+    }
+
+    @Test
+    public void writeTwoPageDoc() throws Exception {
+        PdfDocument doc = new PdfDocument();
+
+        assertEquals(0, doc.getPages().size());
+
+        PdfDocument.Page page0 = doc
+                .startPage(new PdfDocument.PageInfo.Builder(101, 100, 0).create());
+
+        assertEquals(0, doc.getPages().size());
+        doc.finishPage(page0);
+        assertEquals(1, doc.getPages().size());
+        assertTrue(pageInfoEquals(page0.getInfo(), doc.getPages().get(0)));
+
+        File page1File = File.createTempFile("tmp", "pdf", mContext.getCacheDir());
+        try (OutputStream os = new FileOutputStream(page1File)) {
+            doc.writeTo(os);
+        }
+
+        try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(page1File,
+                ParcelFileDescriptor.MODE_READ_ONLY)) {
+            PdfRenderer renderer = new PdfRenderer(fd);
+            assertEquals(1, renderer.getPageCount());
+            try (PdfRenderer.Page page = renderer.openPage(0)) {
+                assertEquals(0, page.getIndex());
+                assertEquals(101, page.getWidth());
+                assertEquals(100, page.getHeight());
+            }
+        }
+
+        PdfDocument.Page page1 = doc
+                .startPage(new PdfDocument.PageInfo.Builder(201, 200, 1).create());
+
+        doc.finishPage(page1);
+        assertEquals(2, doc.getPages().size());
+        assertTrue(pageInfoEquals(page0.getInfo(), doc.getPages().get(0)));
+        assertTrue(pageInfoEquals(page1.getInfo(), doc.getPages().get(1)));
+
+        File page2File = File.createTempFile("tmp", "pdf", mContext.getCacheDir());
+        try (OutputStream os = new FileOutputStream(page2File)) {
+            doc.writeTo(os);
+        }
+
+        try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(page2File,
+                ParcelFileDescriptor.MODE_READ_ONLY)) {
+            PdfRenderer renderer = new PdfRenderer(fd);
+            assertEquals(2, renderer.getPageCount());
+            try (PdfRenderer.Page page = renderer.openPage(0)) {
+                assertEquals(0, page.getIndex());
+                assertEquals(101, page.getWidth());
+                assertEquals(100, page.getHeight());
+            }
+            try (PdfRenderer.Page page = renderer.openPage(1)) {
+                assertEquals(1, page.getIndex());
+                assertEquals(201, page.getWidth());
+                assertEquals(200, page.getHeight());
+            }
+        }
+
+        doc.close();
+    }
+
+    @Test
+    public void writeToNull() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        assertException(() -> doc.writeTo(null), IllegalArgumentException.class);
+        doc.close();
+    }
+
+    @Test
+    public void startNullPage() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        assertException(() -> doc.startPage(null), IllegalArgumentException.class);
+        doc.close();
+    }
+
+    @Test
+    public void finishNullPage() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        assertException(() -> doc.finishPage(null), IllegalArgumentException.class);
+        doc.close();
+    }
+
+    @Test
+    public void zeroWidthPage() throws Exception {
+        assertException(() -> new PdfDocument.PageInfo.Builder(0, 200, 0),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void negativeWidthPage() throws Exception {
+        assertException(() -> new PdfDocument.PageInfo.Builder(-1, 200, 0),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void zeroHeightPage() throws Exception {
+        assertException(() -> new PdfDocument.PageInfo.Builder(100, 0, 0),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void negativeHeightPage() throws Exception {
+        assertException(() -> new PdfDocument.PageInfo.Builder(100, -1, 0),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void negativePageNumber() throws Exception {
+        assertException(() -> new PdfDocument.PageInfo.Builder(100, 200, -1),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void contentRectLeftNegative() throws Exception {
+        assertException(() -> new PdfDocument.PageInfo.Builder(100, 200, 0)
+                        .setContentRect(new Rect(-1, 0, 100, 200)),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void contentRectTopNegative() throws Exception {
+        assertException(() -> new PdfDocument.PageInfo.Builder(100, 200, 0)
+                        .setContentRect(new Rect(0, -1, 100, 200)),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void contentRectRightToHigh() throws Exception {
+        assertException(() -> new PdfDocument.PageInfo.Builder(100, 200, 0)
+                        .setContentRect(new Rect(0, 0, 101, 200)),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void contentRectBottomToHigh() throws Exception {
+        assertException(() -> new PdfDocument.PageInfo.Builder(100, 200, 0)
+                        .setContentRect(new Rect(0, 0, 100, 201)),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void createPageWithFullContentRect() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        Rect contentRect = new Rect(0, 0, 100, 200);
+        PdfDocument.Page page = doc.startPage((new PdfDocument.PageInfo.Builder(100, 200, 0))
+                .setContentRect(contentRect).create());
+        assertEquals(page.getInfo().getContentRect(), contentRect);
+        assertEquals(100, page.getCanvas().getWidth());
+        assertEquals(200, page.getCanvas().getHeight());
+        doc.finishPage(page);
+        doc.close();
+    }
+
+    @Test
+    public void createPageWithPartialContentRect() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        Rect contentRect = new Rect(10, 20, 90, 180);
+        PdfDocument.Page page = doc.startPage((new PdfDocument.PageInfo.Builder(100, 200, 0))
+                .setContentRect(contentRect).create());
+        assertEquals(page.getInfo().getContentRect(), contentRect);
+        assertEquals(80, page.getCanvas().getWidth());
+        assertEquals(160, page.getCanvas().getHeight());
+        doc.finishPage(page);
+        doc.close();
+    }
+
+    @Test
+    public void createPageWithEmptyContentRect() throws Exception {
+        PdfDocument doc = new PdfDocument();
+        Rect contentRect = new Rect(50, 100, 50, 100);
+        PdfDocument.Page page = doc.startPage((new PdfDocument.PageInfo.Builder(100, 200, 0))
+                .setContentRect(contentRect).create());
+        assertEquals(page.getInfo().getContentRect(), contentRect);
+        assertEquals(0, page.getCanvas().getWidth());
+        assertEquals(0, page.getCanvas().getHeight());
+        doc.finishPage(page);
+        doc.close();
+    }
+
+    @Test
+    public void createPageWithInverseContentRect() throws Exception {
+        PdfDocument doc = new PdfDocument();
+
+        // A Rect can have a lower right than left and bottom than top. Of course this does not make
+        // sense for a content rect. For legacy reasons this is treated as we have a empty content
+        // rect.
+        Rect contentRect = new Rect(90, 180, 10, 20);
+        PdfDocument.Page page = doc.startPage((new PdfDocument.PageInfo.Builder(100, 200, 0))
+                .setContentRect(contentRect).create());
+        assertEquals(page.getInfo().getContentRect(), contentRect);
+        assertEquals(0, page.getCanvas().getWidth());
+        assertEquals(0, page.getCanvas().getHeight());
+        doc.finishPage(page);
+
+        doc.close();
+    }
+
+    @Test
+    public void defaultContentRectIsFullRect() throws Exception {
+        PdfDocument.PageInfo info =(new PdfDocument.PageInfo.Builder(100, 200, 0)).create();
+        assertEquals(info.getContentRect(), new Rect(0, 0, 100, 200));
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java b/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java
new file mode 100644
index 0000000..cc3ea7e
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java
@@ -0,0 +1,362 @@
+/*
+ * 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.graphics.pdf.cts;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.cts.R;
+import android.graphics.pdf.PdfRenderer;
+import android.graphics.pdf.PdfRenderer.Page;
+import android.os.ParcelFileDescriptor;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * All test for {@link PdfRenderer} beside the valid transformation parameter tests of {@link
+ * PdfRenderer.Page#render}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class PdfRendererTest {
+    private static final int A5_PORTRAIT_PRINTSCALING_DEFAULT =
+            R.raw.a5_portrait_rgbb_1_6_printscaling_default;
+    private static final int A5_PORTRAIT_PRINTSCALING_NONE =
+            R.raw.a5_portrait_rgbb_1_6_printscaling_none;
+    private static final int TWO_PAGES = R.raw.two_pages;
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    @Test
+    public void constructRendererNull() throws Exception {
+        Utils.assertException(() -> new PdfRenderer(null), NullPointerException.class);
+    }
+
+    @Test
+    @Ignore("Makes all subsequent tests fail")
+    public void constructRendererFromNonPDF() throws Exception {
+        // Open jpg as if it was a PDF
+        ParcelFileDescriptor fd = mContext.getResources().openRawResourceFd(R.raw.testimage)
+                .getParcelFileDescriptor();
+        Utils.assertException(() -> new PdfRenderer(fd), IOException.class);
+    }
+
+    @Test
+    public void useRendererAfterClose() throws Exception {
+        PdfRenderer renderer = Utils.createRenderer(Utils.A4_PORTRAIT, mContext);
+        renderer.close();
+
+        Utils.assertException(renderer::close, IllegalStateException.class);
+        Utils.assertException(renderer::getPageCount, IllegalStateException.class);
+        Utils.assertException(renderer::shouldScaleForPrinting, IllegalStateException.class);
+        Utils.assertException(() -> renderer.openPage(0), IllegalStateException.class);
+    }
+
+    @Test
+    public void usePageAfterClose() throws Exception {
+        PdfRenderer renderer = Utils.createRenderer(Utils.A4_PORTRAIT, mContext);
+        Page page = renderer.openPage(0);
+        page.close();
+
+        // Legacy behavior: The properties are cached, hence they are still available after the page
+        //                  is closed
+        page.getHeight();
+        page.getWidth();
+        page.getIndex();
+        Utils.assertException(page::close, IllegalStateException.class);
+
+        // Legacy support. An IllegalStateException would be nice by unfortunately the legacy
+        // implementation returned NullPointerException
+        Utils.assertException(() -> page.render(null, null, null, Page.RENDER_MODE_FOR_DISPLAY),
+                NullPointerException.class);
+
+        renderer.close();
+    }
+
+    @Test
+    public void closeWithOpenPage() throws Exception {
+        PdfRenderer renderer = Utils.createRenderer(Utils.A4_PORTRAIT, mContext);
+        Page page = renderer.openPage(0);
+
+        Utils.assertException(renderer::close, IllegalStateException.class);
+
+        page.close();
+        renderer.close();
+    }
+
+    @Test
+    public void openTwoPages() throws Exception {
+        try (PdfRenderer renderer = Utils.createRenderer(TWO_PAGES, mContext)) {
+            // Cannot open two pages at once
+            Page page = renderer.openPage(0);
+            Utils.assertException(() -> renderer.openPage(1), IllegalStateException.class);
+
+            page.close();
+        }
+    }
+
+    @Test
+    public void testPageCount() throws Exception {
+        try (PdfRenderer renderer = Utils.createRenderer(TWO_PAGES, mContext)) {
+            assertEquals(2, renderer.getPageCount());
+        }
+    }
+
+    @Test
+    public void testOpenPage() throws Exception {
+        try (PdfRenderer renderer = Utils.createRenderer(TWO_PAGES, mContext)) {
+            Utils.assertException(() -> renderer.openPage(-1), IllegalArgumentException.class);
+            Page page0 = renderer.openPage(0);
+            page0.close();
+            Page page1 = renderer.openPage(1);
+            page1.close();
+            Utils.assertException(() -> renderer.openPage(2), IllegalArgumentException.class);
+        }
+    }
+
+    @Test
+    public void testPageSize() throws Exception {
+        try (PdfRenderer renderer = Utils.createRenderer(Utils.A4_PORTRAIT, mContext)) {
+            try (Page page = renderer.openPage(0)) {
+                assertEquals(Utils.A4_HEIGHT_PTS, page.getHeight());
+                assertEquals(Utils.A4_WIDTH_PTS, page.getWidth());
+            }
+        }
+    }
+
+    @Test
+    public void testPrintScaleDefault() throws Exception {
+        try (PdfRenderer renderer = Utils.createRenderer(Utils.A5_PORTRAIT, mContext)) {
+            assertTrue(renderer.shouldScaleForPrinting());
+        }
+    }
+
+    @Test
+    public void testPrintScalePDF16Default() throws Exception {
+        try (PdfRenderer renderer = Utils
+                .createRenderer(A5_PORTRAIT_PRINTSCALING_DEFAULT, mContext)) {
+            assertTrue(renderer.shouldScaleForPrinting());
+        }
+    }
+
+    @Test
+    public void testPrintScalePDF16None() throws Exception {
+        try (PdfRenderer renderer = Utils.createRenderer(A5_PORTRAIT_PRINTSCALING_NONE, mContext)) {
+            assertFalse(renderer.shouldScaleForPrinting());
+        }
+    }
+
+    /**
+     * Take 16 color probes in the middle of the 16 segments of the page in the following pattern:
+     * <pre>
+     * +----+----+----+----+
+     * |  0 :  1 :  2 :  3 |
+     * +....:....:....:....+
+     * |  4 :  5 :  6 :  7 |
+     * +....:....:....:....+
+     * |  8 :  9 : 10 : 11 |
+     * +....:....:....:....+
+     * | 12 : 13 : 14 : 15 |
+     * +----+----+----+----+
+     * </pre>
+     *
+     * @param bm The bitmap to probe
+     *
+     * @return The color at the probes
+     */
+    private @NonNull int[] getColorProbes(@NonNull Bitmap bm) {
+        int[] probes = new int[16];
+
+        for (int row = 0; row < 4; row++) {
+            for (int column = 0; column < 4; column++) {
+                probes[row * 4 + column] = bm.getPixel((int) (bm.getWidth() * (column + 0.5) / 4),
+                        (int) (bm.getHeight() * (row + 0.5) / 4));
+            }
+        }
+
+        return probes;
+    }
+
+    /**
+     * Implementation for {@link #renderNoTransformationAndComparePointsForScreen} and {@link
+     * #renderNoTransformationAndComparePointsForPrint}.
+     *
+     * @param renderMode The render mode to use
+     *
+     * @throws Exception If anything was unexpected
+     */
+    private void renderNoTransformationAndComparePoints(int renderMode) throws Exception {
+        Bitmap bm = Utils.renderWithTransform(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS,
+                Utils.A4_PORTRAIT, null, null, renderMode, mContext);
+        int[] probes = getColorProbes(bm);
+
+        // Compare rendering to expected result. This ensures that all other tests in this class do
+        // not accidentally all compare empty bitmaps.
+        assertEquals(Color.RED, probes[0]);
+        assertEquals(Color.RED, probes[1]);
+        assertEquals(Color.GREEN, probes[2]);
+        assertEquals(Color.GREEN, probes[3]);
+        assertEquals(Color.RED, probes[4]);
+        assertEquals(Color.RED, probes[5]);
+        assertEquals(Color.GREEN, probes[6]);
+        assertEquals(Color.GREEN, probes[7]);
+        assertEquals(Color.BLUE, probes[8]);
+        assertEquals(Color.BLUE, probes[9]);
+        assertEquals(Color.BLACK, probes[10]);
+        assertEquals(Color.BLACK, probes[11]);
+        assertEquals(Color.BLUE, probes[12]);
+        assertEquals(Color.BLUE, probes[13]);
+        assertEquals(Color.BLACK, probes[14]);
+        assertEquals(Color.BLACK, probes[15]);
+    }
+
+    @Test
+    public void renderNoTransformationAndComparePointsForScreen() throws Exception {
+        renderNoTransformationAndComparePoints(Page.RENDER_MODE_FOR_DISPLAY);
+    }
+
+    @Test
+    public void renderNoTransformationAndComparePointsForPrint() throws Exception {
+        renderNoTransformationAndComparePoints(Page.RENDER_MODE_FOR_PRINT);
+    }
+
+    @Test
+    public void renderPerspective() throws Exception {
+        Matrix transform = new Matrix();
+
+        transform.setValues(new float[] { 1, 1, 1, 1, 1, 1, 1, 1, 1 });
+
+        Utils.assertException(() -> Utils
+                        .renderWithTransform(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS,
+                                Utils.A4_PORTRAIT, null, transform, Page.RENDER_MODE_FOR_DISPLAY,
+                                mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void render45degreeRotationTranslationAndScaleAndClip() throws Exception {
+        Matrix transform = new Matrix();
+        // Rotate on top left corner
+        transform.postRotate(45);
+        // Move
+        transform.postTranslate(Utils.A4_WIDTH_PTS / 4, Utils.A4_HEIGHT_PTS / 4);
+        // Scale to 75%
+        transform.postScale(0.75f, 0.75f);
+        // Clip
+        Rect clip = new Rect(20, 20, Utils.A4_WIDTH_PTS - 20, Utils.A4_HEIGHT_PTS - 20);
+
+        Utils.renderAndCompare(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS, Utils.A4_PORTRAIT, clip,
+                transform, Page.RENDER_MODE_FOR_DISPLAY, mContext);
+    }
+
+    @Test
+    public void renderStreched() throws Exception {
+        Utils.renderAndCompare(Utils.A4_WIDTH_PTS * 4 / 3, Utils.A4_HEIGHT_PTS * 3 / 4,
+                Utils.A4_PORTRAIT, null, null, Page.RENDER_MODE_FOR_DISPLAY, mContext);
+    }
+
+    @Test
+    public void renderWithClip() throws Exception {
+        Rect clip = new Rect(20, 20, Utils.A4_WIDTH_PTS - 50, Utils.A4_HEIGHT_PTS - 50);
+        Utils.renderAndCompare(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS,
+                Utils.A4_PORTRAIT, clip, null, Page.RENDER_MODE_FOR_DISPLAY, mContext);
+    }
+
+    @Test
+    public void renderWithAllClipped() throws Exception {
+        Rect clip = new Rect(Utils.A4_WIDTH_PTS / 2, Utils.A4_HEIGHT_PTS / 2,
+                Utils.A4_WIDTH_PTS / 2, Utils.A4_HEIGHT_PTS / 2);
+        Utils.renderAndCompare(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS, Utils.A4_PORTRAIT, clip,
+                null, Page.RENDER_MODE_FOR_DISPLAY, mContext);
+    }
+
+    @Test
+    public void renderWithBadLowerCornerOfClip() throws Exception {
+        Rect clip = new Rect(0, 0, Utils.A4_WIDTH_PTS + 20, Utils.A4_HEIGHT_PTS + 20);
+        Utils.assertException(() -> Utils
+                        .renderWithTransform(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS,
+                                Utils.A4_PORTRAIT, clip, null, Page.RENDER_MODE_FOR_DISPLAY,
+                                mContext),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderWithBadUpperCornerOfClip() throws Exception {
+        Rect clip = new Rect(-20, -20, Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS);
+        Utils.assertException(() -> Utils
+                        .renderWithTransform(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS,
+                                Utils.A4_PORTRAIT, clip, null, Page.RENDER_MODE_FOR_DISPLAY,
+                                mContext),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderTwoModes() throws Exception {
+        Utils.assertException(() -> Utils
+                .renderWithTransform(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS, Utils.A4_PORTRAIT,
+                        null, null, Page.RENDER_MODE_FOR_DISPLAY | Page.RENDER_MODE_FOR_PRINT,
+                        mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderBadMode() throws Exception {
+        Utils.assertException(() -> Utils
+                .renderWithTransform(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS, Utils.A4_PORTRAIT,
+                        null, null, 1 << 30, mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderAllModes() throws Exception {
+        Utils.assertException(() -> Utils
+                .renderWithTransform(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS, Utils.A4_PORTRAIT,
+                        null, null, -1, mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderNoMode() throws Exception {
+        Utils.assertException(() -> Utils
+                .renderWithTransform(Utils.A4_WIDTH_PTS, Utils.A4_HEIGHT_PTS, Utils.A4_PORTRAIT,
+                        null, null, 0, mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderOnNullBitmap() throws Exception {
+        try (PdfRenderer renderer = Utils.createRenderer(Utils.A4_PORTRAIT, mContext)) {
+            try (Page page = renderer.openPage(0)) {
+                Utils.assertException(() -> page.render(null, null, null, Page.RENDER_MODE_FOR_DISPLAY),
+                        NullPointerException.class);
+            }
+        }
+    }
+
+}
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTransformTest.java b/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTransformTest.java
new file mode 100644
index 0000000..facbd4e
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTransformTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.graphics.pdf.cts;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.pdf.PdfRenderer;
+import android.graphics.pdf.PdfRenderer.Page;
+import android.support.annotation.Nullable;
+import android.support.annotation.RawRes;
+import android.support.test.InstrumentationRegistry;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Test for the {@link PdfRenderer}
+ */
+@RunWith(Parameterized.class)
+public class PdfRendererTransformTest {
+    private Context mContext;
+    private int mWidth;
+    private int mHeight;
+    private int mDocRes;
+    private @Nullable Rect mClipping;
+    private @Nullable Matrix mTransformation;
+    private int mRenderMode;
+
+    public PdfRendererTransformTest(int width, int height, @RawRes int docRes,
+            @Nullable Rect clipping, @Nullable Matrix transformation, int renderMode) {
+        mWidth = width;
+        mHeight = height;
+        mDocRes = docRes;
+        mClipping = clipping;
+        mTransformation = transformation;
+        mRenderMode = renderMode;
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> getParameters() {
+        int[] widths = new int[] { Utils.A4_WIDTH_PTS * 3 / 4, Utils.A4_WIDTH_PTS,
+                Utils.A4_WIDTH_PTS * 4 / 3
+        };
+        int[] heights = new int[] { Utils.A4_HEIGHT_PTS * 3 / 4, Utils.A4_HEIGHT_PTS,
+                Utils.A4_HEIGHT_PTS * 4 / 3
+        };
+        int[] rotations = new int[] { 0, 15, 90, 180 };
+        int[] translations = new int[] { -Utils.A4_HEIGHT_PTS / 2, 0, Utils.A4_HEIGHT_PTS / 2 };
+        float[] scales = { -0.5f, 0, 1, 1.5f };
+
+        Collection<Object[]> params = new ArrayList<>();
+
+        for (int rotation : rotations) {
+            for (float scaleX : scales) {
+                for (float scaleY : scales) {
+                    for (int translateX : translations) {
+                        for (int translateY : translations) {
+                            Matrix transformation = new Matrix();
+                            if (rotation != 0 || translateX != 0 || translateY != 0
+                                    || scaleX != 0 || scaleY != 0) {
+                                if (rotation != 0) {
+                                    transformation.postRotate(rotation);
+                                }
+
+                                if (scaleX != 0 || scaleY != 0) {
+                                    transformation.postScale(scaleX, scaleY);
+                                }
+
+                                if (translateX != 0 || translateY != 0) {
+                                    transformation.postTranslate(translateX,
+                                            translateY);
+                                }
+                            }
+
+                            for (int width : widths) {
+                                for (int height : heights) {
+                                    params.add(
+                                            new Object[] { width, height, Utils.A4_PORTRAIT, null,
+                                                    transformation, Page.RENDER_MODE_FOR_DISPLAY
+                                            });
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return params;
+    }
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    @Test
+    public void test() throws Exception {
+        Utils.renderAndCompare(mWidth, mHeight, mDocRes, mClipping, mTransformation, mRenderMode,
+                mContext);
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/Utils.java b/tests/tests/graphics/src/android/graphics/pdf/cts/Utils.java
new file mode 100644
index 0000000..b6989a7
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/pdf/cts/Utils.java
@@ -0,0 +1,299 @@
+/*
+ * 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.graphics.pdf.cts;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.pdf.PdfRenderer;
+import android.os.ParcelFileDescriptor;
+import android.support.annotation.FloatRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RawRes;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Map;
+
+import static org.junit.Assert.fail;
+
+/**
+ * Utilities for this package
+ */
+class Utils {
+    private static final String LOG_TAG = "Utils";
+
+    private static Map<Integer, File> sFiles = new ArrayMap<>();
+    private static Map<Integer, Bitmap> sRenderedBitmaps = new ArrayMap<>();
+
+    static final int A4_WIDTH_PTS = 595;
+    static final int A4_HEIGHT_PTS = 841;
+    static final int A4_PORTRAIT = android.graphics.cts.R.raw.a4_portrait_rgbb;
+    static final int A5_PORTRAIT = android.graphics.cts.R.raw.a5_portrait_rgbb;
+
+    /**
+     * Create a {@link PdfRenderer} pointing to a file copied from a resource.
+     *
+     * @param docRes  The resource to load
+     * @param context The context to use for creating the renderer
+     *
+     * @return the renderer
+     *
+     * @throws IOException If anything went wrong
+     */
+    static @NonNull PdfRenderer createRenderer(@RawRes int docRes, @NonNull Context context)
+            throws IOException {
+        File pdfFile = sFiles.get(docRes);
+
+        if (pdfFile == null) {
+            pdfFile = File.createTempFile("pdf", null, context.getCacheDir());
+
+            // Copy resource to file so that we can open it as a ParcelFileDescriptor
+            try (OutputStream os = new BufferedOutputStream(new FileOutputStream(pdfFile))) {
+                try (InputStream is = new BufferedInputStream(
+                        context.getResources().openRawResource(docRes))) {
+                    byte buffer[] = new byte[1024];
+
+                    while (true) {
+                        int numRead = is.read(buffer, 0, buffer.length);
+
+                        if (numRead == -1) {
+                            break;
+                        }
+
+                        os.write(Arrays.copyOf(buffer, numRead));
+                    }
+
+                    os.flush();
+                }
+            }
+
+            sFiles.put(docRes, pdfFile);
+        }
+
+        return new PdfRenderer(
+                ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_ONLY));
+    }
+
+    /**
+     * Render a pdf onto a bitmap <u>while</u> applying the transformation <u>in the</u>
+     * PDFRenderer. Hence use PdfRenderer.*'s translation and clipping methods.
+     *
+     * @param bmWidth        The width of the destination bitmap
+     * @param bmHeight       The height of the destination bitmap
+     * @param docRes         The resolution of the doc
+     * @param clipping       The clipping for the PDF document
+     * @param transformation The transformation of the PDF
+     * @param renderMode     The render mode to use to render the PDF
+     * @param context        The context to use for creating the renderer
+     *
+     * @return The rendered bitmap
+     */
+    static @NonNull Bitmap renderWithTransform(int bmWidth, int bmHeight, @RawRes int docRes,
+            @Nullable Rect clipping, @Nullable Matrix transformation, int renderMode,
+            @NonNull Context context)
+            throws IOException {
+        try (PdfRenderer renderer = createRenderer(docRes, context)) {
+            try (PdfRenderer.Page page = renderer.openPage(0)) {
+                Bitmap bm = Bitmap.createBitmap(bmWidth, bmHeight, Bitmap.Config.ARGB_8888);
+
+                page.render(bm, clipping, transformation, renderMode);
+
+                return bm;
+            }
+        }
+    }
+
+    /**
+     * Render a pdf onto a bitmap <u>and then</u> apply then render the resulting bitmap onto
+     * another bitmap while applying the transformation. Hence use canvas' translation and clipping
+     * methods.
+     *
+     * @param bmWidth        The width of the destination bitmap
+     * @param bmHeight       The height of the destination bitmap
+     * @param docRes         The resolution of the doc
+     * @param clipping       The clipping for the PDF document
+     * @param transformation The transformation of the PDF
+     * @param renderMode     The render mode to use to render the PDF
+     * @param context        The context to use for creating the renderer
+     *
+     * @return The rendered bitmap
+     */
+    private static @NonNull Bitmap renderAndThenTransform(int bmWidth, int bmHeight,
+            @RawRes int docRes, @Nullable Rect clipping, @Nullable Matrix transformation,
+            int renderMode, @NonNull Context context) throws IOException {
+        Bitmap renderedBm;
+
+        renderedBm = sRenderedBitmaps.get(docRes);
+
+        if (renderedBm == null) {
+            try (PdfRenderer renderer = Utils.createRenderer(docRes, context)) {
+                try (PdfRenderer.Page page = renderer.openPage(0)) {
+                    renderedBm = Bitmap.createBitmap(page.getWidth(), page.getHeight(),
+                            Bitmap.Config.ARGB_8888);
+                    page.render(renderedBm, null, null, renderMode);
+                }
+            }
+            sRenderedBitmaps.put(docRes, renderedBm);
+        }
+
+        if (transformation == null) {
+            // According to PdfRenderer.page#render transformation == null means that the bitmap
+            // should be stretched to clipping (if provided) or otherwise destination size
+            transformation = new Matrix();
+
+            if (clipping != null) {
+                transformation.postScale((float) clipping.width() / renderedBm.getWidth(),
+                        (float) clipping.height() / renderedBm.getHeight());
+                transformation.postTranslate(clipping.left, clipping.top);
+            } else {
+                transformation.postScale((float) bmWidth / renderedBm.getWidth(),
+                        (float) bmHeight / renderedBm.getHeight());
+            }
+        }
+
+        Bitmap transformedBm = Bitmap.createBitmap(bmWidth, bmHeight, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(transformedBm);
+        canvas.drawBitmap(renderedBm, transformation, null);
+
+        Bitmap clippedBm;
+        if (clipping != null) {
+            clippedBm = Bitmap.createBitmap(bmWidth, bmHeight, Bitmap.Config.ARGB_8888);
+            canvas = new Canvas(clippedBm);
+            canvas.drawBitmap(transformedBm, clipping, clipping, null);
+            transformedBm.recycle();
+        } else {
+            clippedBm = transformedBm;
+        }
+
+        return clippedBm;
+    }
+
+    /**
+     * Get the fraction of non-matching pixels of two bitmaps. 1 == no pixels match, 0 == all pixels
+     * match.
+     *
+     * @param a The first bitmap
+     * @param b The second bitmap
+     *
+     * @return The fraction of non-matching pixels.
+     */
+    private static @FloatRange(from = 0, to = 1) float getNonMatching(@NonNull Bitmap a,
+            @NonNull Bitmap b) {
+        if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
+            return 1;
+        }
+
+        int[] aPx = new int[a.getWidth() * a.getHeight()];
+        int[] bPx = new int[b.getWidth() * b.getHeight()];
+        a.getPixels(aPx, 0, a.getWidth(), 0, 0, a.getWidth(), a.getHeight());
+        b.getPixels(bPx, 0, b.getWidth(), 0, 0, b.getWidth(), b.getHeight());
+
+        int badPixels = 0;
+        for (int i = 0; i < a.getWidth() * a.getHeight(); i++) {
+            if (aPx[i] != bPx[i]) {
+                badPixels++;
+            }
+        }
+
+        return ((float) badPixels) / (a.getWidth() * a.getHeight());
+    }
+
+    /**
+     * Render the PDF two times. Once with applying the transformation and clipping in the {@link
+     * PdfRenderer}. The other time render the PDF onto a bitmap and then clip and transform that
+     * image. The result should be the same beside some minor aliasing.
+     *
+     * @param width          The width of the resulting bitmap
+     * @param height         The height of the resulting bitmap
+     * @param docRes         The resource of the PDF document
+     * @param clipping       The clipping to apply
+     * @param transformation The transformation to apply
+     * @param renderMode     The render mode to use
+     * @param context        The context to use for creating the renderer
+     *
+     * @throws IOException
+     */
+    static void renderAndCompare(int width, int height, @RawRes int docRes,
+            @Nullable Rect clipping, @Nullable Matrix transformation, int renderMode,
+            @NonNull Context context) throws IOException {
+        Bitmap a = renderWithTransform(width, height, docRes, clipping, transformation,
+                renderMode, context);
+        Bitmap b = renderAndThenTransform(width, height, docRes, clipping, transformation,
+                renderMode, context);
+
+        try {
+            // We allow 1% aliasing error
+            float nonMatching = getNonMatching(a, b);
+
+            if (nonMatching == 0) {
+                Log.d(LOG_TAG, "bitmaps match");
+            } else if (nonMatching > 0.01) {
+                fail("Testing width:" + width + ", height:" + height + ", docRes:" + docRes +
+                        ", clipping:" + clipping + ", transform:" + transformation + ". Bitmaps " +
+                        "differ by " + Math.ceil(nonMatching * 10000) / 100 +
+                        "%. That is too much.");
+            } else {
+                Log.d(LOG_TAG, "bitmaps differ by " + Math.ceil(nonMatching * 10000) / 100 + "%");
+            }
+        } finally {
+            a.recycle();
+            b.recycle();
+        }
+    }
+
+    /**
+     * Run a runnable and expect and exception of a certain type.
+     *
+     * @param r             The {@link Invokable} to run
+     * @param expectedClass The expected exception type
+     */
+    static void assertException(@NonNull Invokable r,
+            @NonNull Class<? extends Exception> expectedClass) {
+        try {
+            r.run();
+        } catch (Exception e) {
+            if (e.getClass().isAssignableFrom(expectedClass)) {
+                return;
+            } else {
+                Log.e(LOG_TAG, "Incorrect exception", e);
+                throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
+                        + e.getClass().getName());
+            }
+        }
+
+        throw new AssertionError("No exception thrown");
+    }
+
+    /**
+     * A runnable that can throw an exception.
+     */
+    interface Invokable {
+        void run() throws Exception;
+    }
+}
diff --git a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
index 77c6da1..5a76816 100644
--- a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -25,6 +25,7 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import javax.microedition.khronos.egl.EGL10;
@@ -61,20 +62,16 @@
         int detectedMajorVersion = getDetectedMajorVersion();
         int reportedVersion = getVersionFromActivityManager(mActivity);
 
-        assertEquals("Detected OpenGL ES major version " + detectedMajorVersion
-                + " but Activity Manager is reporting " +  getMajorVersion(reportedVersion)
-                + " (Check ro.opengles.version)",
-                detectedMajorVersion, getMajorVersion(reportedVersion));
         assertEquals("Reported OpenGL ES version from ActivityManager differs from PackageManager",
                 reportedVersion, getVersionFromPackageManager(mActivity));
 
-        assertGlVersionString(1);
+        assertGlVersionString(1, 1);
         if (detectedMajorVersion == 2) {
             restartActivityWithClientVersion(2);
-            assertGlVersionString(2);
+            assertGlVersionString(2, getMinorVersion(reportedVersion));
         } else if (detectedMajorVersion == 3) {
             restartActivityWithClientVersion(3);
-            assertGlVersionString(3);
+            assertGlVersionString(3, getMinorVersion(reportedVersion));
         }
     }
 
@@ -123,14 +120,11 @@
         restartActivityWithClientVersion(3);
 
         String extensions = mActivity.getExtensionsString();
-        if (!hasExtension(extensions, "ANDROID_extension_pack_es31a")) {
-            assertFalse("FEATURE_OPENGLES_EXTENSION_PACK is available but ANDROID_extension_pack_es31a isn't in the extension list",
-                    hasAepFeature);
-            return;
-        }
-
-        assertTrue("ANDROID_extension_pack_es31a is present, but support is incomplete",
-                mActivity.getAepEs31Support());
+        boolean hasAepExtension = hasExtension(extensions, "GL_ANDROID_extension_pack_es31a");
+        assertEquals("System feature FEATURE_OPENGLES_EXTENSION_PACK is "
+            + (hasAepFeature ? "" : "not ") + "available, but extension GL_ANDROID_extension_pack_es31a is "
+            + (hasAepExtension ? "" : "not ") + "in the OpenGL ES extension list.",
+            hasAepFeature, hasAepExtension);
     }
 
     public void testOpenGlEsVersionForVrHighPerformance() throws InterruptedException {
@@ -288,15 +282,21 @@
     }
 
     /**
-     * Check that the version string has some form of "Open GL ES X.Y" in it where X is the major
-     * version and Y must be some digit.
+     * Check that the version string has the form "OpenGL ES(-CM)? (\d+)\.(\d+)", where the two
+     * numbers match the major and minor parameters.
      */
-    private void assertGlVersionString(int majorVersion) throws InterruptedException {
-        String versionString = "" + majorVersion;
-        String message = "OpenGL version string '" + mActivity.getVersionString()
-                + "' is not " + majorVersion + ".0+.";
-        assertTrue(message, Pattern.matches(".*OpenGL.*ES.*" + versionString + "\\.\\d.*",
-                mActivity.getVersionString()));
+    private void assertGlVersionString(int major, int minor) throws InterruptedException {
+        Matcher matcher = Pattern.compile("OpenGL ES(?:-CM)? (\\d+)\\.(\\d+).*")
+                                 .matcher(mActivity.getVersionString());
+        assertTrue("OpenGL ES version string is not of the required form "
+            + "'OpenGL ES(-CM)? (\\d+)\\.(\\d+).*'",
+            matcher.matches());
+        int stringMajor = Integer.parseInt(matcher.group(1));
+        int stringMinor = Integer.parseInt(matcher.group(2));
+        assertEquals("GL_VERSION string doesn't match ActivityManager major version (check ro.opengles.version property)",
+            major, stringMajor);
+        assertEquals("GL_VERSION string doesn't match ActivityManager minor version (check ro.opengles.version property)",
+            minor, stringMinor);
     }
 
     /** Restart {@link GLSurfaceViewCtsActivity} with a specific client version. */
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
index 6f183d5..39d1285 100644
--- a/tests/tests/icu/Android.mk
+++ b/tests/tests/icu/Android.mk
@@ -30,9 +30,12 @@
 
 # The aim of this package is to run tests against the implementation in use by
 # the current android system.
+LOCAL_JAVA_LIBRARIES := cts-core-test-runner
+
 LOCAL_STATIC_JAVA_LIBRARIES := \
-	cts-core-test-runner \
-	android-icu4j-tests
+	android-icu4j-tests \
+	ctstestrunner \
+	android-support-test
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/tests/jni/Android.mk b/tests/tests/jni/Android.mk
index 7a9504d..4a81a85 100644
--- a/tests/tests/jni/Android.mk
+++ b/tests/tests/jni/Android.mk
@@ -30,7 +30,7 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
 LOCAL_JNI_SHARED_LIBRARIES := libjnitest libnativehelper_compat_libc++
 
diff --git a/tests/tests/jni/libjnitest/helper.c b/tests/tests/jni/libjnitest/helper.c
index 8f7f2f8..2281795 100644
--- a/tests/tests/jni/libjnitest/helper.c
+++ b/tests/tests/jni/libjnitest/helper.c
@@ -70,6 +70,7 @@
             free(result);
             if (newResult == NULL) {
                 // Shouldn't happen, but deal as gracefully as possible.
+                va_end(args);
                 return NULL;
             }
             result = newResult;
diff --git a/tests/tests/jni/libjnitest/macroized_tests.c b/tests/tests/jni/libjnitest/macroized_tests.c
index 76b5481..130b378 100644
--- a/tests/tests/jni/libjnitest/macroized_tests.c
+++ b/tests/tests/jni/libjnitest/macroized_tests.c
@@ -192,6 +192,7 @@
             "returnBoolean", "()Z");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -240,6 +241,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -295,6 +297,7 @@
             "returnByte", "()B");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -343,6 +346,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -398,6 +402,7 @@
             "returnShort", "()S");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -446,6 +451,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -501,6 +507,7 @@
             "returnChar", "()C");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -549,6 +556,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -604,6 +612,7 @@
             "returnInt", "()I");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -652,6 +661,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -707,6 +717,7 @@
             "returnLong", "()J");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -755,6 +766,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -810,6 +822,7 @@
             "returnFloat", "()F");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -858,6 +871,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -913,6 +927,7 @@
             "returnDouble", "()D");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -961,6 +976,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -1016,6 +1032,7 @@
             "nop", "()V");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -1064,6 +1081,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -1119,6 +1137,7 @@
             "returnString", "()Ljava/lang/String;");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -1171,6 +1190,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -1240,6 +1260,7 @@
             "takeOneOfEach", "(DFJICSBZLjava/lang/String;)Z");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -1299,6 +1320,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
@@ -1361,6 +1383,7 @@
             "(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)Z");
 
     if (method == NULL) {
+        va_end(args);
         return msg;
     }
 
@@ -1441,6 +1464,7 @@
             break;
         }
         default: {
+            va_end(args);
             return failure("shouldn't happen");
         }
     }
diff --git a/tests/tests/keystore/Android.mk b/tests/tests/keystore/Android.mk
index 4688846..8fe7a3b 100644
--- a/tests/tests/keystore/Android.mk
+++ b/tests/tests/keystore/Android.mk
@@ -26,6 +26,7 @@
 LOCAL_JAVA_LIBRARIES := bouncycastle
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
+        android-support-test \
         core-tests-support \
         ctsdeviceutil \
         ctstestrunner \
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index eda78e8..d61556d 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -44,7 +44,7 @@
 # include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestserver ctstestrunner ndkaudio
+LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestserver ctstestrunner ndkaudio android-support-test
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni libaudio_jni libnativehelper_compat_libc++ libndkaudioLib
 
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 9125f87..76d9199 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -2820,6 +2820,32 @@
     }
 
     /**
+     * Returns true if there exists a codec supporting the given MIME type that meets the
+     * minimum specification for VR high performance requirements.
+     *
+     * The requirements are as follows:
+     *   - At least 243000 blocks per second (where blocks are defined as 16x16 -- note this
+     *   is equivalent to 1920x1080@30fps)
+     *   - Feature adaptive-playback present
+     */
+    private static boolean doesMimeTypeHaveMinimumSpecVrReadyCodec(String mimeType) {
+        List<CodecCapabilities> caps = getCodecCapabilitiesForMimeType(mimeType);
+        for (CodecCapabilities c : caps) {
+            if (!c.isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback)) {
+                continue;
+            }
+
+            if (!c.getVideoCapabilities().areSizeAndRateSupported(1920, 1080, 30.0)) {
+                continue;
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
      * Returns true if there exists a codec supporting the given MIME type that meets VR high
      * performance requirements.
      *
@@ -2939,6 +2965,13 @@
             return;
         }
 
+        // Test minimum mandatory requirements.
+        assertTrue(doesMimeTypeHaveMinimumSpecVrReadyCodec(MediaFormat.MIMETYPE_VIDEO_HEVC));
+        decodeInParallel(
+                // using the 60fps sample to save on apk size, but decoding only at 30fps @ 5Mbps
+                R.raw.bbb_s2_1920x1080_mp4_hevc_mp41_10mbps_60fps_aac_lc_6ch_384kbps_22050hz,
+                300, 30 /* fps */, 1);
+
         boolean hevcIsReady = doesMimeTypeHaveVrReadyCodec(MediaFormat.MIMETYPE_VIDEO_HEVC);
         if (!hevcIsReady) {
             MediaUtils.skipTest(TAG, "HEVC isn't required to be VR ready");
@@ -2958,6 +2991,13 @@
             return;
         }
 
+        // Test minimum mandatory requirements.
+        assertTrue(doesMimeTypeHaveMinimumSpecVrReadyCodec(MediaFormat.MIMETYPE_VIDEO_VP9));
+        decodeInParallel(
+                // using the 60fps sample to save on apk size, but decoding only at 30fps @ 5Mbps
+                R.raw.bbb_s2_1920x1080_webm_vp9_0p41_10mbps_60fps_vorbis_6ch_384kbps_22050hz,
+                300, 30 /* fps */, 1);
+
         boolean vp9IsReady = doesMimeTypeHaveVrReadyCodec(MediaFormat.MIMETYPE_VIDEO_VP9);
         if (!vp9IsReady) {
             MediaUtils.skipTest(TAG, "VP9 isn't required to be VR ready");
diff --git a/tests/tests/media/src/android/media/cts/IvfWriter.java b/tests/tests/media/src/android/media/cts/IvfWriter.java
index 075f73c..36fb679 100644
--- a/tests/tests/media/src/android/media/cts/IvfWriter.java
+++ b/tests/tests/media/src/android/media/cts/IvfWriter.java
@@ -16,6 +16,8 @@
 
 package android.media.cts;
 
+import android.media.MediaFormat;
+
 import java.io.IOException;
 import java.io.RandomAccessFile;
 
@@ -34,6 +36,7 @@
     private int mScale;
     private int mRate;
     private int mFrameCount;
+    private String mMimeType;
 
     /**
      * Initializes the IVF file writer.
@@ -43,15 +46,17 @@
      * with this timebase value.
      *
      * @param filename   name of the IVF file
+     * @param mimeType   mime type of the codec
      * @param width      frame width
      * @param height     frame height
      * @param scale      timebase scale (or numerator of the timebase fraction)
      * @param rate       timebase rate (or denominator of the timebase fraction)
      */
-    public IvfWriter(String filename,
-                     int width, int height,
-                     int scale, int rate) throws IOException {
+    public IvfWriter(
+            String filename, String mimeType, int width, int height, int scale,
+            int rate) throws IOException {
         mOutputFile = new RandomAccessFile(filename, "rw");
+        mMimeType = mimeType;
         mWidth = width;
         mHeight = height;
         mScale = scale;
@@ -67,11 +72,12 @@
      * Microsecond timebase is default for OMX thus stagefright.
      *
      * @param filename   name of the IVF file
+     * @param mimeType   mime type of the codec
      * @param width      frame width
      * @param height     frame height
      */
-    public IvfWriter(String filename, int width, int height) throws IOException {
-        this(filename, width, height, 1, 1000000);
+    public IvfWriter(String filename, String mimeType, int width, int height) throws IOException {
+        this(filename, mimeType, width, height, 1, 1000000);
     }
 
     /**
@@ -80,7 +86,7 @@
     public void close() throws IOException{
         // Write header now
         mOutputFile.seek(0);
-        mOutputFile.write(makeIvfHeader(mFrameCount, mWidth, mHeight, mScale, mRate));
+        mOutputFile.write(makeIvfHeader(mFrameCount, mWidth, mHeight, mScale, mRate, mMimeType));
         mOutputFile.close();
     }
 
@@ -107,7 +113,8 @@
      * @param scale      timebase scale (or numerator of the timebase fraction)
      * @param rate       timebase rate (or denominator of the timebase fraction)
      */
-    private static byte[] makeIvfHeader(int frameCount, int width, int height, int scale, int rate){
+    private static byte[] makeIvfHeader(
+            int frameCount, int width, int height, int scale, int rate, String mimeType) {
         byte[] ivfHeader = new byte[32];
         ivfHeader[0] = 'D';
         ivfHeader[1] = 'K';
@@ -117,7 +124,7 @@
         lay16Bits(ivfHeader, 6, 32);  // header size
         ivfHeader[8] = 'V';  // fourcc
         ivfHeader[9] = 'P';
-        ivfHeader[10] = '8';
+        ivfHeader[10] = (byte) (MediaFormat.MIMETYPE_VIDEO_VP8.equals(mimeType) ? '8' : '9');
         ivfHeader[11] = '0';
         lay16Bits(ivfHeader, 12, width);
         lay16Bits(ivfHeader, 14, height);
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
index 23f464e..56e2a6f 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.test.InstrumentationTestCase;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -30,6 +31,17 @@
 public class MediaBrowserTest extends InstrumentationTestCase {
     // The maximum time to wait for an operation.
     private static final long TIME_OUT_MS = 3000L;
+
+    /**
+     * To check {@link MediaBrowser#unsubscribe} works properly,
+     * we notify to the browser after the unsubscription that the media items have changed.
+     * Then {@link MediaBrowser.SubscriptionCallback#onChildrenLoaded} should not be called.
+     *
+     * The measured time from calling {@link StubMediaBrowserService#notifyChildrenChanged}
+     * to {@link MediaBrowser.SubscriptionCallback#onChildrenLoaded} being called is about 50ms.
+     * So we make the thread sleep for 100ms to properly check that the callback is not called.
+     */
+    private static final long SLEEP_MS = 100L;
     private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
             "android.media.cts", "android.media.cts.StubMediaBrowserService");
     private static final ComponentName TEST_INVALID_BROWSER_SERVICE = new ComponentName(
@@ -56,7 +68,12 @@
                 mMediaBrowser.getSessionToken());
 
         mMediaBrowser.disconnect();
-        assertEquals(false, mMediaBrowser.isConnected());
+        new PollingCheck(TIME_OUT_MS) {
+            @Override
+            protected boolean check() {
+                return !mMediaBrowser.isConnected();
+            }
+        }.run();
     }
 
     public void testConnectTwice() {
@@ -116,6 +133,21 @@
             assertEquals(StubMediaBrowserService.MEDIA_ID_CHILDREN[i],
                     mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
         }
+
+        // Test unsubscribe.
+        resetCallbacks();
+        mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT);
+
+        // After unsubscribing, make StubMediaBrowserService notify that the children are changed.
+        StubMediaBrowserService.sInstance.notifyChildrenChanged(
+                StubMediaBrowserService.MEDIA_ID_ROOT);
+        try {
+            Thread.sleep(SLEEP_MS);
+        } catch (InterruptedException e) {
+            fail("Unexpected InterruptedException occurred.");
+        }
+        // onChildrenLoaded should not be called.
+        assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
     }
 
     public void testSubscribeWithOptions() {
@@ -150,6 +182,21 @@
                         mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
             }
         }
+
+        // Test unsubscribe with callback argument.
+        resetCallbacks();
+        mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+
+        // After unsubscribing, make StubMediaBrowserService notify that the children are changed.
+        StubMediaBrowserService.sInstance.notifyChildrenChanged(
+                StubMediaBrowserService.MEDIA_ID_ROOT);
+        try {
+            Thread.sleep(SLEEP_MS);
+        } catch (InterruptedException e) {
+            fail("Unexpected InterruptedException occurred.");
+        }
+        // onChildrenLoaded should not be called.
+        assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
     }
 
     public void testSubscribeInvalidItem() {
@@ -192,6 +239,111 @@
                 mSubscriptionCallback.mLastOptions.getInt(MediaBrowser.EXTRA_PAGE_SIZE));
     }
 
+    public void testUnsubscribeForMultipleSubscriptions() {
+        createMediaBrowser(TEST_BROWSER_SERVICE);
+        connectMediaBrowserService();
+        final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
+        final int pageSize = 1;
+
+        // Subscribe four pages, one item per page.
+        for (int page = 0; page < 4; page++) {
+            final StubSubscriptionCallback callback = new StubSubscriptionCallback();
+            subscriptionCallbacks.add(callback);
+
+            Bundle options = new Bundle();
+            options.putInt(MediaBrowser.EXTRA_PAGE, page);
+            options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
+            mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options, callback);
+
+            // Each onChildrenLoaded() must be called.
+            new PollingCheck(TIME_OUT_MS) {
+                @Override
+                protected boolean check() {
+                    return callback.mChildrenLoadedWithOptionCount == 1;
+                }
+            }.run();
+        }
+
+        // Reset callbacks and unsubscribe.
+        for (StubSubscriptionCallback callback : subscriptionCallbacks) {
+            callback.reset();
+        }
+        mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT);
+
+        // After unsubscribing, make StubMediaBrowserService notify that the children are changed.
+        StubMediaBrowserService.sInstance.notifyChildrenChanged(
+                StubMediaBrowserService.MEDIA_ID_ROOT);
+        try {
+            Thread.sleep(SLEEP_MS);
+        } catch (InterruptedException e) {
+            fail("Unexpected InterruptedException occurred.");
+        }
+
+        // onChildrenLoaded should not be called.
+        for (StubSubscriptionCallback callback : subscriptionCallbacks) {
+            assertEquals(0, callback.mChildrenLoadedWithOptionCount);
+        }
+    }
+
+    public void testUnsubscribeWithSubscriptionCallbackForMultipleSubscriptions() {
+        createMediaBrowser(TEST_BROWSER_SERVICE);
+        connectMediaBrowserService();
+        final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
+        final int pageSize = 1;
+
+        // Subscribe four pages, one item per page.
+        for (int page = 0; page < 4; page++) {
+            final StubSubscriptionCallback callback = new StubSubscriptionCallback();
+            subscriptionCallbacks.add(callback);
+
+            Bundle options = new Bundle();
+            options.putInt(MediaBrowser.EXTRA_PAGE, page);
+            options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
+            mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options, callback);
+
+            // Each onChildrenLoaded() must be called.
+            new PollingCheck(TIME_OUT_MS) {
+                @Override
+                protected boolean check() {
+                    return callback.mChildrenLoadedWithOptionCount == 1;
+                }
+            }.run();
+        }
+
+        // Unsubscribe existing subscriptions one-by-one.
+        final int[] orderOfRemovingCallbacks = {2, 0, 3, 1};
+        for (int i = 0; i < orderOfRemovingCallbacks.length; i++) {
+            // Reset callbacks
+            for (StubSubscriptionCallback callback : subscriptionCallbacks) {
+                callback.reset();
+            }
+
+            // Remove one subscription
+            mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT,
+                    subscriptionCallbacks.get(orderOfRemovingCallbacks[i]));
+
+            // Make StubMediaBrowserService notify that the children are changed.
+            StubMediaBrowserService.sInstance.notifyChildrenChanged(
+                    StubMediaBrowserService.MEDIA_ID_ROOT);
+            try {
+                Thread.sleep(SLEEP_MS);
+            } catch (InterruptedException e) {
+                fail("Unexpected InterruptedException occurred.");
+            }
+
+            // Only the remaining subscriptionCallbacks should be called.
+            for (int j = 0; j < 4; j++) {
+                int childrenLoadedWithOptionsCount = subscriptionCallbacks
+                        .get(orderOfRemovingCallbacks[j]).mChildrenLoadedWithOptionCount;
+                if (j <= i) {
+                    assertEquals(0, childrenLoadedWithOptionsCount);
+                } else {
+                    assertEquals(1, childrenLoadedWithOptionsCount);
+                }
+            }
+        }
+    }
+
     public void testGetItem() {
         resetCallbacks();
         createMediaBrowser(TEST_BROWSER_SERVICE);
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index 446cd3c..3c751a5 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -54,12 +54,8 @@
     private static final int TIMEOUT_US = 1000000;  // 1 sec
     private static final int IFRAME_INTERVAL = 10;          // 10 seconds between I-frames
 
-    private final MediaCodecList mRegularCodecs =
-            new MediaCodecList(MediaCodecList.REGULAR_CODECS);
     private final MediaCodecList mAllCodecs =
             new MediaCodecList(MediaCodecList.ALL_CODECS);
-    private final MediaCodecInfo[] mRegularInfos =
-            mRegularCodecs.getCodecInfos();
     private final MediaCodecInfo[] mAllInfos =
             mAllCodecs.getCodecInfos();
 
@@ -388,7 +384,7 @@
         // check if there is an adaptive decoder for each
         for (String mime : supportedFormats) {
             skipped = false;
-            // implicit assumption that QVGA video is always valid.
+            // implicit assumption that QCIF video is always valid.
             MediaFormat format = MediaFormat.createVideoFormat(mime, 176, 144);
             format.setFeatureEnabled(CodecCapabilities.FEATURE_AdaptivePlayback, true);
             String codec = mAllCodecs.findDecoderForFormat(format);
@@ -498,7 +494,7 @@
                 MediaFormat format = null;
                 try {
                     codec = MediaCodec.createByCodecName(info.getName());
-                    // implicit assumption that QVGA video is always valid.
+                    // implicit assumption that QCIF video is always valid.
                     format = createReasonableVideoFormat(caps, mime, isEncoder, 176, 144);
                     format.setInteger(
                             MediaFormat.KEY_COLOR_FORMAT,
diff --git a/tests/tests/media/src/android/media/cts/MediaControllerTest.java b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
index b8ec617..a6da2d9 100644
--- a/tests/tests/media/src/android/media/cts/MediaControllerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
@@ -15,6 +15,7 @@
  */
 package android.media.cts;
 
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.Rating;
 import android.media.VolumeProvider;
@@ -52,6 +53,22 @@
         mController = mSession.getController();
     }
 
+    public void testGetPackageName() {
+        assertEquals(getContext().getPackageName(), mController.getPackageName());
+    }
+
+    public void testGetRatingType() {
+        assertEquals("Default rating type of a session must be Rating.RATING_NONE",
+                Rating.RATING_NONE, mController.getRatingType());
+
+        mSession.setRatingType(Rating.RATING_5_STARS);
+        assertEquals(Rating.RATING_5_STARS, mController.getRatingType());
+    }
+
+    public void testGetSessionToken() throws Exception {
+        assertEquals(mSession.getSessionToken(), mController.getSessionToken());
+    }
+
     public void testSendCommand() throws Exception {
         synchronized (mWaitLock) {
             mCallback.reset();
@@ -243,6 +260,23 @@
         }
     }
 
+    public void testPlaybackInfo() {
+        final int playbackType = MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+        final int volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
+        final int maxVolume = 10;
+        final int currentVolume = 3;
+
+        AudioAttributes audioAttributes = new AudioAttributes.Builder().build();
+        MediaController.PlaybackInfo info = new MediaController.PlaybackInfo(
+                playbackType, audioAttributes, volumeControl, maxVolume, currentVolume);
+
+        assertEquals(playbackType, info.getPlaybackType());
+        assertEquals(audioAttributes, info.getAudioAttributes());
+        assertEquals(volumeControl, info.getVolumeControl());
+        assertEquals(maxVolume, info.getMaxVolume());
+        assertEquals(currentVolume, info.getCurrentVolume());
+    }
+
     private class MediaSessionCallback extends MediaSession.Callback {
         private long mSeekPosition;
         private long mQueueItemId;
@@ -415,7 +449,7 @@
         @Override
         public void onCustomAction(String action, Bundle extras) {
             synchronized (mWaitLock) {
-                mOnCustomActionCalled= true;
+                mOnCustomActionCalled = true;
                 mAction = action;
                 mExtras = extras;
                 mWaitLock.notify();
diff --git a/tests/tests/media/src/android/media/cts/MediaItemTest.java b/tests/tests/media/src/android/media/cts/MediaItemTest.java
index 4eefaa7..dc12b97 100644
--- a/tests/tests/media/src/android/media/cts/MediaItemTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaItemTest.java
@@ -40,6 +40,7 @@
         assertEquals(MediaItem.FLAG_BROWSABLE, mediaItem.getFlags());
         assertTrue(mediaItem.isBrowsable());
         assertFalse(mediaItem.isPlayable());
+        assertEquals(0, mediaItem.describeContents());
 
         // Test writeToParcel
         Parcel p = Parcel.obtain();
@@ -62,6 +63,7 @@
         assertEquals(MediaItem.FLAG_PLAYABLE, mediaItem.getFlags());
         assertFalse(mediaItem.isBrowsable());
         assertTrue(mediaItem.isPlayable());
+        assertEquals(0, mediaItem.describeContents());
 
         // Test writeToParcel
         Parcel p = Parcel.obtain();
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index dffb653..25cf0ba 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -449,7 +449,7 @@
     }
 
     public void testRecorderAudio() throws Exception {
-        if (!hasMicrophone() || !hasAmrNb()) {
+        if (!hasMicrophone() || !hasAac()) {
             MediaUtils.skipTest("no audio codecs or microphone");
             return;
         }
@@ -457,7 +457,7 @@
         assertEquals(0, mMediaRecorder.getMaxAmplitude());
         mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
         mMediaRecorder.setOutputFile(OUTPUT_PATH);
-        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
         mMediaRecorder.setAudioChannels(AUDIO_NUM_CHANNELS);
         mMediaRecorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE_HZ);
         mMediaRecorder.setAudioEncodingBitRate(AUDIO_BIT_RATE_IN_BPS);
@@ -465,14 +465,14 @@
     }
 
     public void testOnInfoListener() throws Exception {
-        if (!hasMicrophone() || !hasAmrNb()) {
+        if (!hasMicrophone() || !hasAac()) {
             MediaUtils.skipTest("no audio codecs or microphone");
             return;
         }
         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
         mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
         mMediaRecorder.setMaxDuration(MAX_DURATION_MSEC);
-        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
         mMediaRecorder.prepare();
         mMediaRecorder.start();
         Thread.sleep(RECORD_TIME_MS);
@@ -480,7 +480,7 @@
     }
 
     public void testSetMaxDuration() throws Exception {
-        if (!hasMicrophone() || !hasAmrNb()) {
+        if (!hasMicrophone() || !hasAac()) {
             MediaUtils.skipTest("no audio codecs or microphone");
             return;
         }
@@ -491,7 +491,7 @@
         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
         mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
         mMediaRecorder.setMaxDuration((int)durationMs);
-        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
         mMediaRecorder.prepare();
         mMediaRecorder.start();
         long startTimeMs = System.currentTimeMillis();
@@ -556,13 +556,13 @@
     }
 
     public void testOnErrorListener() throws Exception {
-        if (!hasMicrophone() || !hasAmrNb()) {
+        if (!hasMicrophone() || !hasAac()) {
             MediaUtils.skipTest("no audio codecs or microphone");
             return;
         }
         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
         mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
-        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
 
         recordMedia(MAX_FILE_SIZE, mOutFile);
         // TODO: how can we trigger a recording error?
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTest.java b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
index 3ebe6e4..4ed6a78 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
@@ -16,6 +16,7 @@
 package android.media.cts;
 
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.media.AudioAttributes;
@@ -31,9 +32,9 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
+import android.view.KeyEvent;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -230,7 +231,7 @@
     }
 
     /**
-     * Tests for setPlaybackToLocal and setPlaybackToRemote.
+     * Test {@link MediaSession#setPlaybackToLocal} and {@link MediaSession#setPlaybackToRemote}.
      */
     public void testPlaybackToLocalAndRemote() throws Exception {
         MediaController controller = mSession.getController();
@@ -291,7 +292,91 @@
     }
 
     /**
-     * Tests MediaSession.QueueItem.
+     * Test {@link MediaSession.Callback#onMediaButtonEvent}.
+     */
+    public void testCallbackOnMediaButtonEvent() throws Exception {
+        MediaSessionCallback sessionCallback = new MediaSessionCallback();
+        mSession.setCallback(sessionCallback, new Handler(Looper.getMainLooper()));
+        mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
+        mSession.setActive(true);
+
+        Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON).setComponent(
+                new ComponentName(getContext(), getContext().getClass()));
+        PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, mediaButtonIntent, 0);
+        mSession.setMediaButtonReceiver(pi);
+
+        long supportedActions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE
+                | PlaybackState.ACTION_PLAY_PAUSE | PlaybackState.ACTION_STOP
+                | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS
+                | PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_REWIND;
+
+        // Set state to STATE_PLAYING to get higher priority.
+        PlaybackState defaultState = new PlaybackState.Builder().setActions(supportedActions)
+                .setState(PlaybackState.STATE_PLAYING, 0L, 0.0f).build();
+        mSession.setPlaybackState(defaultState);
+
+        synchronized (mWaitLock) {
+            sessionCallback.reset();
+            simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(sessionCallback.mOnPlayCalled);
+
+            sessionCallback.reset();
+            simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PAUSE);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(sessionCallback.mOnPauseCalled);
+
+            sessionCallback.reset();
+            simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_NEXT);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(sessionCallback.mOnSkipToNextCalled);
+
+            sessionCallback.reset();
+            simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(sessionCallback.mOnSkipToPreviousCalled);
+
+            sessionCallback.reset();
+            simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_STOP);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(sessionCallback.mOnStopCalled);
+
+            sessionCallback.reset();
+            simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(sessionCallback.mOnFastForwardCalled);
+
+            sessionCallback.reset();
+            simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_REWIND);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(sessionCallback.mOnRewindCalled);
+
+            // Test PLAY_PAUSE button twice.
+            // First, simulate PLAY_PAUSE button while in STATE_PAUSED.
+            sessionCallback.reset();
+            mSession.setPlaybackState(new PlaybackState.Builder().setActions(supportedActions)
+                    .setState(PlaybackState.STATE_PAUSED, 0L, 0.0f).build());
+            simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(sessionCallback.mOnPlayCalled);
+
+            // Next, simulate PLAY_PAUSE button while in STATE_PLAYING.
+            sessionCallback.reset();
+            mSession.setPlaybackState(new PlaybackState.Builder().setActions(supportedActions)
+                    .setState(PlaybackState.STATE_PLAYING, 0L, 0.0f).build());
+            simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(sessionCallback.mOnPauseCalled);
+        }
+    }
+
+    private void simulateMediaKeyInput(int keyCode) {
+        mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+        mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
+    }
+
+    /**
+     * Tests {@link MediaSession.QueueItem}.
      */
     public void testQueueItem() {
         QueueItem item = new QueueItem(new MediaDescription.Builder()
@@ -299,6 +384,7 @@
         assertEquals(TEST_QUEUE_ID, item.getQueueId());
         assertEquals("media-id", item.getDescription().getMediaId());
         assertEquals("title", item.getDescription().getTitle());
+        assertEquals(0, item.describeContents());
 
         Parcel p = Parcel.obtain();
         item.writeToParcel(p, 0);
@@ -448,4 +534,80 @@
             }
         }
     }
+
+    private class MediaSessionCallback extends MediaSession.Callback {
+        private boolean mOnPlayCalled;
+        private boolean mOnPauseCalled;
+        private boolean mOnStopCalled;
+        private boolean mOnFastForwardCalled;
+        private boolean mOnRewindCalled;
+        private boolean mOnSkipToPreviousCalled;
+        private boolean mOnSkipToNextCalled;
+
+        public void reset() {
+            mOnPlayCalled = false;
+            mOnPauseCalled = false;
+            mOnStopCalled = false;
+            mOnFastForwardCalled = false;
+            mOnRewindCalled = false;
+            mOnSkipToPreviousCalled = false;
+            mOnSkipToNextCalled = false;
+        }
+
+        @Override
+        public void onPlay() {
+            synchronized (mWaitLock) {
+                mOnPlayCalled = true;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
+        public void onPause() {
+            synchronized (mWaitLock) {
+                mOnPauseCalled = true;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
+        public void onStop() {
+            synchronized (mWaitLock) {
+                mOnStopCalled = true;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
+        public void onFastForward() {
+            synchronized (mWaitLock) {
+                mOnFastForwardCalled = true;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
+        public void onRewind() {
+            synchronized (mWaitLock) {
+                mOnRewindCalled = true;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
+        public void onSkipToPrevious() {
+            synchronized (mWaitLock) {
+                mOnSkipToPreviousCalled = true;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
+        public void onSkipToNext() {
+            synchronized (mWaitLock) {
+                mOnSkipToNextCalled = true;
+                mWaitLock.notify();
+            }
+        }
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/PlaybackStateTest.java b/tests/tests/media/src/android/media/cts/PlaybackStateTest.java
new file mode 100644
index 0000000..ba96784
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/PlaybackStateTest.java
@@ -0,0 +1,263 @@
+/*
+ * 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.media.cts;
+
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+
+/**
+ * Test {@link android.media.session.PlaybackState}.
+ */
+public class PlaybackStateTest extends AndroidTestCase {
+
+    private static final long TEST_POSITION = 20000L;
+    private static final long TEST_BUFFERED_POSITION = 15000L;
+    private static final long TEST_UPDATE_TIME = 100000L;
+    private static final long TEST_ACTIONS =
+            PlaybackState.ACTION_PLAY | PlaybackState.ACTION_STOP | PlaybackState.ACTION_SEEK_TO;
+    private static final long TEST_QUEUE_ITEM_ID = 23L;
+    private static final float TEST_PLAYBACK_SPEED = 3.0f;
+    private static final float TEST_PLAYBACK_SPEED_ON_REWIND = -2.0f;
+    private static final float DELTA = 1e-7f;
+
+    private static final String TEST_ERROR_MSG = "test-error-msg";
+    private static final String TEST_CUSTOM_ACTION = "test-custom-action";
+    private static final String TEST_CUSTOM_ACTION_NAME = "test-custom-action-name";
+    private static final int TEST_ICON_RESOURCE_ID = android.R.drawable.ic_media_next;
+
+    private static final String EXTRAS_KEY = "test-key";
+    private static final String EXTRAS_VALUE = "test-value";
+
+    /**
+     * Test default values of {@link PlaybackState}.
+     */
+    public void testBuilder() {
+        PlaybackState state = new PlaybackState.Builder().build();
+
+        assertEquals(new ArrayList<PlaybackState.CustomAction>(), state.getCustomActions());
+        assertEquals(0, state.getState());
+        assertEquals(0L, state.getPosition());
+        assertEquals(0L, state.getBufferedPosition());
+        assertEquals(0.0f, state.getPlaybackSpeed(), DELTA);
+        assertEquals(0L, state.getActions());
+        assertNull(state.getErrorMessage());
+        assertEquals(0L, state.getLastPositionUpdateTime());
+        assertEquals(MediaSession.QueueItem.UNKNOWN_ID, state.getActiveQueueItemId());
+        assertNull(state.getExtras());
+    }
+
+    /**
+     * Test following setter methods of {@link PlaybackState.Builder}:
+     * {@link PlaybackState.Builder#setState(int, long, float)}
+     * {@link PlaybackState.Builder#setActions(long)}
+     * {@link PlaybackState.Builder#setActiveQueueItemId(long)}
+     * {@link PlaybackState.Builder#setBufferedPosition(long)}
+     * {@link PlaybackState.Builder#setErrorMessage(CharSequence)}
+     * {@link PlaybackState.Builder#setExtras(Bundle)}
+     */
+    public void testBuilder_setterMethods() {
+        Bundle extras = new Bundle();
+        extras.putString(EXTRAS_KEY, EXTRAS_VALUE);
+
+        PlaybackState state = new PlaybackState.Builder()
+                .setState(PlaybackState.STATE_PLAYING, TEST_POSITION, TEST_PLAYBACK_SPEED)
+                .setActions(TEST_ACTIONS)
+                .setActiveQueueItemId(TEST_QUEUE_ITEM_ID)
+                .setBufferedPosition(TEST_BUFFERED_POSITION)
+                .setErrorMessage(TEST_ERROR_MSG)
+                .setExtras(extras)
+                .build();
+        assertEquals(PlaybackState.STATE_PLAYING, state.getState());
+        assertEquals(TEST_POSITION, state.getPosition());
+        assertEquals(TEST_PLAYBACK_SPEED, state.getPlaybackSpeed(), DELTA);
+        assertEquals(TEST_ACTIONS, state.getActions());
+        assertEquals(TEST_QUEUE_ITEM_ID, state.getActiveQueueItemId());
+        assertEquals(TEST_BUFFERED_POSITION, state.getBufferedPosition());
+        assertEquals(TEST_ERROR_MSG, state.getErrorMessage().toString());
+        assertEquals(EXTRAS_VALUE, state.getExtras().get(EXTRAS_KEY));
+    }
+
+    /**
+     * Test {@link PlaybackState.Builder#setState(int, long, float, long)}.
+     */
+    public void testBuilder_setStateWithUpdateTime() {
+        PlaybackState state = new PlaybackState.Builder().setState(
+                PlaybackState.STATE_REWINDING, TEST_POSITION,
+                TEST_PLAYBACK_SPEED_ON_REWIND, TEST_UPDATE_TIME).build();
+        assertEquals(PlaybackState.STATE_REWINDING, state.getState());
+        assertEquals(TEST_POSITION, state.getPosition());
+        assertEquals(TEST_PLAYBACK_SPEED_ON_REWIND, state.getPlaybackSpeed(), DELTA);
+        assertEquals(TEST_UPDATE_TIME, state.getLastPositionUpdateTime());
+    }
+
+    /**
+     * Test {@link PlaybackState.Builder#addCustomAction(String, String, int)}.
+     */
+    public void testBuilder_addCustomAction() {
+        ArrayList<PlaybackState.CustomAction> actions = new ArrayList<>();
+        PlaybackState.Builder builder = new PlaybackState.Builder();
+
+        for (int i = 0; i < 5; i++) {
+            actions.add(new PlaybackState.CustomAction.Builder(
+                    TEST_CUSTOM_ACTION + i, TEST_CUSTOM_ACTION_NAME + i, TEST_ICON_RESOURCE_ID + i)
+                    .build());
+            builder.addCustomAction(
+                    TEST_CUSTOM_ACTION + i, TEST_CUSTOM_ACTION_NAME + i, TEST_ICON_RESOURCE_ID + i);
+        }
+
+        PlaybackState state = builder.build();
+        assertEquals(actions.size(), state.getCustomActions().size());
+        for (int i = 0; i < actions.size(); i++) {
+            assertCustomActionEquals(actions.get(i), state.getCustomActions().get(i));
+        }
+    }
+
+    /**
+     * Test {@link PlaybackState.Builder#addCustomAction(PlaybackState.CustomAction)}.
+     */
+    public void testBuilder_addCustomActionWithCustomActionObject() {
+        Bundle extras = new Bundle();
+        extras.putString(EXTRAS_KEY, EXTRAS_VALUE);
+
+        ArrayList<PlaybackState.CustomAction> actions = new ArrayList<>();
+        PlaybackState.Builder builder = new PlaybackState.Builder();
+
+        for (int i = 0; i < 5; i++) {
+            actions.add(new PlaybackState.CustomAction.Builder(
+                    TEST_CUSTOM_ACTION + i, TEST_CUSTOM_ACTION_NAME + i, TEST_ICON_RESOURCE_ID + i)
+                    .setExtras(extras)
+                    .build());
+            builder.addCustomAction(new PlaybackState.CustomAction.Builder(
+                    TEST_CUSTOM_ACTION + i, TEST_CUSTOM_ACTION_NAME + i, TEST_ICON_RESOURCE_ID + i)
+                    .setExtras(extras)
+                    .build());
+        }
+
+        PlaybackState state = builder.build();
+        assertEquals(actions.size(), state.getCustomActions().size());
+        for (int i = 0; i < actions.size(); i++) {
+            assertCustomActionEquals(actions.get(i), state.getCustomActions().get(i));
+        }
+    }
+
+    /**
+     * Test {@link PlaybackState#writeToParcel(Parcel, int)}.
+     */
+    public void testWriteToParcel() {
+        Bundle extras = new Bundle();
+        extras.putString(EXTRAS_KEY, EXTRAS_VALUE);
+
+        PlaybackState.CustomAction customAction1 = new PlaybackState.CustomAction
+                .Builder(TEST_CUSTOM_ACTION, TEST_CUSTOM_ACTION_NAME, TEST_ICON_RESOURCE_ID)
+                .setExtras(extras)
+                .build();
+
+        PlaybackState.Builder builder =
+                new PlaybackState.Builder().setState(PlaybackState.STATE_CONNECTING, TEST_POSITION,
+                TEST_PLAYBACK_SPEED, TEST_UPDATE_TIME)
+                .setActions(TEST_ACTIONS)
+                .setActiveQueueItemId(TEST_QUEUE_ITEM_ID)
+                .setBufferedPosition(TEST_BUFFERED_POSITION)
+                .setErrorMessage(TEST_ERROR_MSG)
+                .setExtras(extras);
+
+        for (int i = 0; i < 5; i++) {
+            builder.addCustomAction(new PlaybackState.CustomAction.Builder(
+                    TEST_CUSTOM_ACTION + i, TEST_CUSTOM_ACTION_NAME + i, TEST_ICON_RESOURCE_ID + i)
+                    .setExtras(extras)
+                    .build());
+        }
+        PlaybackState state = builder.build();
+
+        Parcel parcel = Parcel.obtain();
+        state.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        PlaybackState stateOut = PlaybackState.CREATOR.createFromParcel(parcel);
+        assertEquals(PlaybackState.STATE_CONNECTING, stateOut.getState());
+        assertEquals(TEST_POSITION, stateOut.getPosition());
+        assertEquals(TEST_PLAYBACK_SPEED, stateOut.getPlaybackSpeed(), DELTA);
+        assertEquals(TEST_UPDATE_TIME, stateOut.getLastPositionUpdateTime());
+        assertEquals(TEST_BUFFERED_POSITION, stateOut.getBufferedPosition());
+        assertEquals(TEST_ACTIONS, stateOut.getActions());
+        assertEquals(TEST_QUEUE_ITEM_ID, stateOut.getActiveQueueItemId());
+        assertEquals(TEST_ERROR_MSG, stateOut.getErrorMessage());
+        assertEquals(EXTRAS_VALUE, stateOut.getExtras().get(EXTRAS_KEY));
+
+        assertEquals(state.getCustomActions().size(), stateOut.getCustomActions().size());
+        for (int i = 0; i < state.getCustomActions().size(); i++) {
+            assertCustomActionEquals(state.getCustomActions().get(i),
+                    stateOut.getCustomActions().get(i));
+        }
+        parcel.recycle();
+    }
+
+    /**
+     * Test {@link PlaybackState#describeContents()}.
+     */
+    public void testDescribeContents() {
+        assertEquals(0, new PlaybackState.Builder().build().describeContents());
+    }
+
+    /**
+     * Test {@link PlaybackState.CustomAction}.
+     */
+    public void testCustomAction() {
+        Bundle extras = new Bundle();
+        extras.putString(EXTRAS_KEY, EXTRAS_VALUE);
+
+        // Test Builder/Getters
+        PlaybackState.CustomAction customAction = new PlaybackState.CustomAction
+                .Builder(TEST_CUSTOM_ACTION, TEST_CUSTOM_ACTION_NAME, TEST_ICON_RESOURCE_ID)
+                .setExtras(extras)
+                .build();
+        assertEquals(TEST_CUSTOM_ACTION, customAction.getAction());
+        assertEquals(TEST_CUSTOM_ACTION_NAME, customAction.getName().toString());
+        assertEquals(TEST_ICON_RESOURCE_ID, customAction.getIcon());
+        assertEquals(EXTRAS_VALUE, customAction.getExtras().get(EXTRAS_KEY));
+
+        // Test describeContents
+        assertEquals(0, customAction.describeContents());
+
+        // Test writeToParcel
+        Parcel parcel = Parcel.obtain();
+        customAction.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        assertCustomActionEquals(customAction,
+                PlaybackState.CustomAction.CREATOR.createFromParcel(parcel));
+        parcel.recycle();
+    }
+
+    private void assertCustomActionEquals(PlaybackState.CustomAction action1,
+            PlaybackState.CustomAction action2) {
+        assertEquals(action1.getAction(), action2.getAction());
+        assertEquals(action1.getName(), action2.getName());
+        assertEquals(action1.getIcon(), action2.getIcon());
+
+        // To be the same, two extras should be both null or both not null.
+        assertEquals(action1.getExtras() != null, action2.getExtras() != null);
+        if (action1.getExtras() != null) {
+            assertEquals(action1.getExtras().get(EXTRAS_KEY), action2.getExtras().get(EXTRAS_KEY));
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java b/tests/tests/media/src/android/media/cts/VpxCodecTestBase.java
similarity index 96%
rename from tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
rename to tests/tests/media/src/android/media/cts/VpxCodecTestBase.java
index 0395ec7..ea72225 100644
--- a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
+++ b/tests/tests/media/src/android/media/cts/VpxCodecTestBase.java
@@ -43,17 +43,18 @@
 import java.util.concurrent.CountDownLatch;
 
 /**
- * Verification test for vp8 encoder and decoder.
+ * Verification test for vpx encoder and decoder.
  *
  * A raw yv12 stream is encoded at various settings and written to an IVF
  * file. Encoded stream bitrate and key frame interval are checked against target values.
- * The stream is later decoded by vp8 decoder to verify frames are decodable and to
+ * The stream is later decoded by the decoder to verify frames are decodable and to
  * calculate PSNR values for various bitrates.
  */
-public class Vp8CodecTestBase extends AndroidTestCase {
+public class VpxCodecTestBase extends AndroidTestCase {
 
-    protected static final String TAG = "VP8CodecTestBase";
+    protected static final String TAG = "VPxCodecTestBase";
     protected static final String VP8_MIME = MediaFormat.MIMETYPE_VIDEO_VP8;
+    protected static final String VP9_MIME = MediaFormat.MIMETYPE_VIDEO_VP9;
     private static final String GOOGLE_CODEC_PREFIX = "omx.google.";
     protected static final String SDCARD_DIR =
             Environment.getExternalStorageDirectory().getAbsolutePath();
@@ -91,7 +92,7 @@
     }
 
     /**
-     *  VP8 codec properties generated by getVp8CodecProperties() function.
+     *  VPx codec properties generated by getVpxCodecProperties() function.
      */
     private class CodecProperties {
         CodecProperties(String codecName, int colorFormat) {
@@ -102,12 +103,12 @@
             return codecName.toLowerCase().startsWith(GOOGLE_CODEC_PREFIX);
         }
 
-        public final String codecName; // OpenMax component name for VP8 codec.
+        public final String codecName; // OpenMax component name for VPx codec.
         public final int colorFormat;  // Color format supported by codec.
     }
 
     /**
-     * Function to find VP8 codec.
+     * Function to find VPx codec.
      *
      * Iterates through the list of available codecs and tries to find
      * VPX codec, which can support either YUV420 planar or NV12 color formats.
@@ -197,7 +198,9 @@
         int inputResourceId;
         // Name of the IVF file to write encoded bitsream
         public String outputIvfFilename;
-        // Force to use Google VP8 encoder.
+        // Mime Type of the Encoded content.
+        public String codecMimeType;
+        // Force to use Google VPx encoder.
         boolean forceGoogleEncoder;
         // Number of frames to encode.
         int frameCount;
@@ -236,6 +239,7 @@
     protected ArrayList<EncoderOutputStreamParameters> getDefaultEncodingParameterList(
             String inputYuvName,
             String outputIvfBaseName,
+            String codecMimeType,
             int encodeSeconds,
             int[] resolutionScales,
             int frameWidth,
@@ -258,8 +262,10 @@
             params.scaledYuvFilename = SDCARD_DIR + File.separator +
                     outputIvfBaseName + resolutionScales[i]+ ".yuv";
             params.inputResourceId = R.raw.football_qvga;
+            params.codecMimeType = codecMimeType;
+            String codecSuffix = VP8_MIME.equals(codecMimeType) ? "vp8" : "vp9";
             params.outputIvfFilename = SDCARD_DIR + File.separator +
-                    outputIvfBaseName + resolutionScales[i] + ".ivf";
+                    outputIvfBaseName + resolutionScales[i] + "_" + codecSuffix + ".ivf";
             params.forceGoogleEncoder = false;
             params.frameCount = encodeSeconds * frameRate;
             params.frameRate = frameRate;
@@ -286,6 +292,7 @@
     protected EncoderOutputStreamParameters getDefaultEncodingParameters(
             String inputYuvName,
             String outputIvfBaseName,
+            String codecMimeType,
             int encodeSeconds,
             int frameWidth,
             int frameHeight,
@@ -298,6 +305,7 @@
         return getDefaultEncodingParameterList(
                 inputYuvName,
                 outputIvfBaseName,
+                codecMimeType,
                 encodeSeconds,
                 scaleValues,
                 frameWidth,
@@ -500,17 +508,18 @@
      * md5 sum comparison wouldn't work.)
      *
      * Indeed, MediaCodec will raise an IllegalStateException
-     * whenever vp8 decoder fails to decode a frame, and
+     * whenever vpx decoder fails to decode a frame, and
      * this test uses that fact to verify the bitstream.
      *
      * @param inputIvfFilename  The name of the IVF file containing encoded bitsream.
      * @param outputYuvFilename The name of the output YUV file (optional).
      * @param frameRate         Frame rate of input file in frames per second
-     * @param forceGoogleDecoder    Force to use Google VP8 decoder.
+     * @param forceGoogleDecoder    Force to use Google VPx decoder.
      */
     protected ArrayList<MediaCodec.BufferInfo> decode(
             String inputIvfFilename,
             String outputYuvFilename,
+            String codecMimeType,
             int frameRate,
             boolean forceGoogleDecoder) throws Exception {
         ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
@@ -528,7 +537,7 @@
 
         // Create decoder.
         MediaFormat format = MediaFormat.createVideoFormat(
-                VP8_MIME, ivf.getWidth(), ivf.getHeight());
+                codecMimeType, ivf.getWidth(), ivf.getHeight());
         CodecProperties properties = getVpxCodecProperties(
                 false /* encoder */, format, forceGoogleDecoder);
         if (properties == null) {
@@ -1243,13 +1252,13 @@
     }
 
     /**
-     * Vp8 encoding loop supporting encoding single streams with an option
+     * Vpx encoding loop supporting encoding single streams with an option
      * to run in a looper thread and use buffer ready notification callbacks.
      *
      * Output stream is described by encodingParams parameters.
      *
      * MediaCodec will raise an IllegalStateException
-     * whenever vp8 encoder fails to encode a frame.
+     * whenever vpx encoder fails to encode a frame.
      *
      * Color format of input file should be YUV420, and frameWidth,
      * frameHeight should be supplied correctly as raw input file doesn't
@@ -1268,7 +1277,8 @@
 
         // Create minimal media format signifying desired output.
         MediaFormat format = MediaFormat.createVideoFormat(
-                VP8_MIME, streamParams.frameWidth, streamParams.frameHeight);
+                streamParams.codecMimeType, streamParams.frameWidth,
+                streamParams.frameHeight);
         format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
         CodecProperties properties = getVpxCodecProperties(
                 true, format, streamParams.forceGoogleEncoder);
@@ -1280,7 +1290,8 @@
         InputStream yuvStream = OpenFileOrResourceId(
                 streamParams.inputYuvFilename, streamParams.inputResourceId);
         IvfWriter ivf = new IvfWriter(
-                streamParams.outputIvfFilename, streamParams.frameWidth, streamParams.frameHeight);
+                streamParams.outputIvfFilename, streamParams.codecMimeType,
+                streamParams.frameWidth, streamParams.frameHeight);
 
         // Create a media format signifying desired output.
         if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
@@ -1416,12 +1427,12 @@
     }
 
     /**
-     * Vp8 encoding run in a looper thread and use buffer ready callbacks.
+     * Vpx encoding run in a looper thread and use buffer ready callbacks.
      *
      * Output stream is described by encodingParams parameters.
      *
      * MediaCodec will raise an IllegalStateException
-     * whenever vp8 encoder fails to encode a frame.
+     * whenever vpx encoder fails to encode a frame.
      *
      * Color format of input file should be YUV420, and frameWidth,
      * frameHeight should be supplied correctly as raw input file doesn't
@@ -1443,7 +1454,8 @@
 
         // Create minimal media format signifying desired output.
         MediaFormat format = MediaFormat.createVideoFormat(
-                VP8_MIME, streamParams.frameWidth, streamParams.frameHeight);
+                streamParams.codecMimeType, streamParams.frameWidth,
+                streamParams.frameHeight);
         format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
         CodecProperties properties = getVpxCodecProperties(
                 true, format, streamParams.forceGoogleEncoder);
@@ -1453,7 +1465,8 @@
 
         // Open input/output
         IvfWriter ivf = new IvfWriter(
-                streamParams.outputIvfFilename, streamParams.frameWidth, streamParams.frameHeight);
+                streamParams.outputIvfFilename, streamParams.codecMimeType,
+                streamParams.frameWidth, streamParams.frameHeight);
 
         // Create a media format signifying desired output.
         if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
@@ -1495,13 +1508,13 @@
     }
 
     /**
-     * Vp8 encoding loop supporting encoding multiple streams at a time.
+     * Vpx encoding loop supporting encoding multiple streams at a time.
      * Each output stream is described by encodingParams parameters allowing
      * simultaneous encoding of various resolutions, bitrates with an option to
      * control key frame and dynamic bitrate for each output stream indepandently.
      *
      * MediaCodec will raise an IllegalStateException
-     * whenever vp8 encoder fails to encode a frame.
+     * whenever vpx encoder fails to encode a frame.
      *
      * Color format of input file should be YUV420, and frameWidth,
      * frameHeight should be supplied correctly as raw input file doesn't
@@ -1546,8 +1559,9 @@
             int bitrate = params.bitrateSet[0];
 
             // Create minimal media format signifying desired output.
-            format[i] = MediaFormat.createVideoFormat(VP8_MIME,
-                    params.frameWidth, params.frameHeight);
+            format[i] = MediaFormat.createVideoFormat(
+                    params.codecMimeType, params.frameWidth,
+                    params.frameHeight);
             format[i].setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
             CodecProperties properties = getVpxCodecProperties(
                     true, format[i], params.forceGoogleEncoder);
@@ -1572,7 +1586,9 @@
             yuvStream[i] = new FileInputStream(params.scaledYuvFilename);
 
             // Create IVF writer
-            ivf[i] = new IvfWriter(params.outputIvfFilename, params.frameWidth, params.frameHeight);
+            ivf[i] = new IvfWriter(
+                    params.outputIvfFilename, params.codecMimeType,
+                    params.frameWidth, params.frameHeight);
 
             // Frame buffer
             int frameSize = params.frameWidth * params.frameHeight * 3 / 2;
@@ -1731,8 +1747,8 @@
     /**
      * Some encoding statistics.
      */
-    protected class Vp8EncodingStatistics {
-        Vp8EncodingStatistics() {
+    protected class VpxEncodingStatistics {
+        VpxEncodingStatistics() {
             mBitrates = new ArrayList<Integer>();
             mFrames = new ArrayList<Integer>();
             mKeyFrames = new ArrayList<Integer>();
@@ -1756,9 +1772,9 @@
      * mKeyFrames array will contain the position of key frames in the encoded stream and
      * mKeyFrameInterval - average key frame interval.
      */
-    protected Vp8EncodingStatistics computeEncodingStatistics(int encoderId,
+    protected VpxEncodingStatistics computeEncodingStatistics(int encoderId,
             ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
-        Vp8EncodingStatistics statistics = new Vp8EncodingStatistics();
+        VpxEncodingStatistics statistics = new VpxEncodingStatistics();
 
         int totalSize = 0;
         int frames = 0;
@@ -1838,18 +1854,18 @@
         return statistics;
     }
 
-    protected Vp8EncodingStatistics computeEncodingStatistics(
+    protected VpxEncodingStatistics computeEncodingStatistics(
             ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
         return computeEncodingStatistics(0, bufferInfos);
     }
 
-    protected ArrayList<Vp8EncodingStatistics> computeSimulcastEncodingStatistics(
+    protected ArrayList<VpxEncodingStatistics> computeSimulcastEncodingStatistics(
             ArrayList<ArrayList<MediaCodec.BufferInfo>> bufferInfos) {
         int numCodecs = bufferInfos.size();
-        ArrayList<Vp8EncodingStatistics> statistics = new ArrayList<Vp8EncodingStatistics>();
+        ArrayList<VpxEncodingStatistics> statistics = new ArrayList<VpxEncodingStatistics>();
 
         for (int i = 0; i < numCodecs; i++) {
-            Vp8EncodingStatistics currentStatistics =
+            VpxEncodingStatistics currentStatistics =
                     computeEncodingStatistics(i, bufferInfos.get(i));
             statistics.add(currentStatistics);
         }
@@ -1872,8 +1888,8 @@
     /**
      * Decoding PSNR statistics.
      */
-    protected class Vp8DecodingStatistics {
-        Vp8DecodingStatistics() {
+    protected class VpxDecodingStatistics {
+        VpxDecodingStatistics() {
             mMinimumPSNR = Integer.MAX_VALUE;
         }
         public double mAveragePSNR;
@@ -1901,13 +1917,13 @@
      * set of reference and decoded video frames.
      * Runs PSNR calculation for the full duration of the decoded data.
      */
-    protected Vp8DecodingStatistics computeDecodingStatistics(
+    protected VpxDecodingStatistics computeDecodingStatistics(
             String referenceYuvFilename,
             int referenceYuvRawId,
             String decodedYuvFilename,
             int width,
             int height) throws Exception {
-        Vp8DecodingStatistics statistics = new Vp8DecodingStatistics();
+        VpxDecodingStatistics statistics = new VpxDecodingStatistics();
         InputStream referenceStream =
                 OpenFileOrResourceId(referenceYuvFilename, referenceYuvRawId);
         InputStream decodedStream = new FileInputStream(decodedYuvFilename);
diff --git a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java b/tests/tests/media/src/android/media/cts/VpxEncoderTest.java
similarity index 85%
rename from tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
rename to tests/tests/media/src/android/media/cts/VpxEncoderTest.java
index 5552f6c..0e9c940 100644
--- a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VpxEncoderTest.java
@@ -28,14 +28,14 @@
 import java.util.Arrays;
 
 /**
- * Verification test for vp8 encoder and decoder.
+ * Verification test for vp8/vp9 encoder and decoder.
  *
  * A raw yv12 stream is encoded at various settings and written to an IVF
  * file. Encoded stream bitrate and key frame interval are checked against target values.
- * The stream is later decoded by vp8 decoder to verify frames are decodable and to
+ * The stream is later decoded by vp8/vp9 decoder to verify frames are decodable and to
  * calculate PSNR values for various bitrates.
  */
-public class Vp8EncoderTest extends Vp8CodecTestBase {
+public class VpxEncoderTest extends VpxCodecTestBase {
 
     private static final String ENCODED_IVF_BASE = "football";
     private static final String INPUT_YUV = null;
@@ -54,9 +54,9 @@
     private static final int[] TEST_BITRATES_SET = { 300000, 500000, 700000, 900000 };
     // Maximum allowed bitrate variation from the target value.
     private static final double MAX_BITRATE_VARIATION = 0.2;
-    // Average PSNR values for reference Google VP8 codec for the above bitrates.
+    // Average PSNR values for reference Google VPx codec for the above bitrates.
     private static final double[] REFERENCE_AVERAGE_PSNR = { 33.1, 35.2, 36.6, 37.8 };
-    // Minimum PSNR values for reference Google VP8 codec for the above bitrates.
+    // Minimum PSNR values for reference Google VPx codec for the above bitrates.
     private static final double[] REFERENCE_MINIMUM_PSNR = { 25.9, 27.5, 28.4, 30.3 };
     // Maximum allowed average PSNR difference of encoder comparing to reference Google encoder.
     private static final double MAX_AVERAGE_PSNR_DIFFERENCE = 2;
@@ -75,13 +75,13 @@
     private static final int MAX_KEYFRAME_INTERVAL_VARIATION = 3;
 
     /**
-     * A basic test for VP8 encoder.
+     * A basic test for VPx encoder.
      *
      * Encodes 9 seconds of raw stream with default configuration options,
      * and then decodes it to verify the bitstream.
      * Also checks the average bitrate is within MAX_BITRATE_VARIATION of the target value.
      */
-    public void testBasic() throws Exception {
+    private void internalTestBasic(String codecMimeType) throws Exception {
         int encodeSeconds = 9;
         boolean skipped = true;
 
@@ -89,6 +89,7 @@
             EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                     INPUT_YUV,
                     ENCODED_IVF_BASE,
+                    codecMimeType,
                     encodeSeconds,
                     WIDTH,
                     HEIGHT,
@@ -102,14 +103,14 @@
             }
             skipped = false;
 
-            Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+            VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
 
             assertEquals("Stream bitrate " + statistics.mAverageBitrate +
                     " is different from the target " + targetBitrate,
                     targetBitrate, statistics.mAverageBitrate,
                     MAX_BITRATE_VARIATION * targetBitrate);
 
-            decode(params.outputIvfFilename, null, FPS, params.forceGoogleEncoder);
+            decode(params.outputIvfFilename, null, codecMimeType, FPS, params.forceGoogleEncoder);
         }
 
         if (skipped) {
@@ -118,13 +119,13 @@
     }
 
     /**
-     * Asynchronous encoding test for VP8 encoder.
+     * Asynchronous encoding test for VPx encoder.
      *
      * Encodes 9 seconds of raw stream using synchronous and asynchronous calls.
      * Checks the PSNR difference between the encoded and decoded output and reference yuv input
      * does not change much for two different ways of the encoder call.
      */
-    public void testAsyncEncoding() throws Exception {
+    private void internalTestAsyncEncoding(String codecMimeType) throws Exception {
         int encodeSeconds = 9;
 
         // First test the encoder running in a looper thread with buffer callbacks enabled.
@@ -132,6 +133,7 @@
         EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                 INPUT_YUV,
                 ENCODED_IVF_BASE,
+                codecMimeType,
                 encodeSeconds,
                 WIDTH,
                 HEIGHT,
@@ -145,8 +147,8 @@
             return;
         }
         computeEncodingStatistics(bufInfos);
-        decode(params.outputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
-        Vp8DecodingStatistics statisticsAsync = computeDecodingStatistics(
+        decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+        VpxDecodingStatistics statisticsAsync = computeDecodingStatistics(
                 params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
                 params.frameWidth, params.frameHeight);
 
@@ -156,6 +158,7 @@
         params = getDefaultEncodingParameters(
                 INPUT_YUV,
                 ENCODED_IVF_BASE,
+                codecMimeType,
                 encodeSeconds,
                 WIDTH,
                 HEIGHT,
@@ -169,8 +172,8 @@
             return;
         }
         computeEncodingStatistics(bufInfos);
-        decode(params.outputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
-        Vp8DecodingStatistics statisticsSync = computeDecodingStatistics(
+        decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+        VpxDecodingStatistics statisticsSync = computeDecodingStatistics(
                 params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
                 params.frameWidth, params.frameHeight);
 
@@ -193,12 +196,13 @@
      * Encodes 9 seconds of raw stream and requests a sync frame every second (30 frames).
      * The test does not verify the output stream.
      */
-    public void testSyncFrame() throws Exception {
+    private void internalTestSyncFrame(String codecMimeType) throws Exception {
         int encodeSeconds = 9;
 
         EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                 INPUT_YUV,
                 ENCODED_IVF_BASE,
+                codecMimeType,
                 encodeSeconds,
                 WIDTH,
                 HEIGHT,
@@ -214,7 +218,7 @@
             return;
         }
 
-        Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+        VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
 
         // First check if we got expected number of key frames.
         int actualKeyFrames = statistics.mKeyFrames.size();
@@ -242,13 +246,14 @@
      * Run the the encoder for 12 seconds. Request changes to the
      * bitrate after 6 seconds and ensure the encoder responds.
      */
-    public void testDynamicBitrateChange() throws Exception {
+    private void internalTestDynamicBitrateChange(String codecMimeType) throws Exception {
         int encodeSeconds = 12;    // Encoding sequence duration in seconds.
         int[] bitrateTargetValues = { 400000, 800000 };  // List of bitrates to test.
 
         EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                 INPUT_YUV,
                 ENCODED_IVF_BASE,
+                codecMimeType,
                 encodeSeconds,
                 WIDTH,
                 HEIGHT,
@@ -274,7 +279,7 @@
             return;
         }
 
-        Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+        VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
 
         // Calculate actual average bitrates  for every [stepSeconds] second.
         int[] bitrateActualValues = new int[bitrateTargetValues.length];
@@ -309,11 +314,11 @@
       * and then run parallel encoding and decoding of the same streams.
       * Compares average bitrate and PSNR for sequential and parallel runs.
       */
-     public void testParallelEncodingAndDecoding() throws Exception {
+     private void internalTestParallelEncodingAndDecoding(String codecMimeType) throws Exception {
          // check for encoder up front, as by the time we detect lack of
          // encoder support, we may have already started decoding.
          MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-         MediaFormat format = MediaFormat.createVideoFormat(VP8_MIME, WIDTH, HEIGHT);
+         MediaFormat format = MediaFormat.createVideoFormat(codecMimeType, WIDTH, HEIGHT);
          if (mcl.findEncoderForFormat(format) == null) {
              Log.i(TAG, "SKIPPING testParallelEncodingAndDecoding(): no suitable encoder found");
              return;
@@ -327,6 +332,7 @@
          final EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                  INPUT_YUV,
                  ENCODED_IVF_BASE,
+                 codecMimeType,
                  encodeSeconds,
                  WIDTH,
                  HEIGHT,
@@ -340,7 +346,7 @@
              public void run() {
                  try {
                      ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
-                     Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+                     VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
                      bitrate[0] = statistics.mAverageBitrate;
                  } catch (Exception e) {
                      Log.e(TAG, "Encoder error: " + e.toString());
@@ -351,8 +357,8 @@
          Runnable runDecoder = new Runnable() {
              public void run() {
                  try {
-                     decode(inputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
-                     Vp8DecodingStatistics statistics = computeDecodingStatistics(
+                     decode(inputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+                     VpxDecodingStatistics statistics = computeDecodingStatistics(
                             params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
                             params.frameWidth, params.frameHeight);
                      psnr[0] = statistics.mAveragePSNR;
@@ -410,7 +416,7 @@
      * Video streams with higher bitrates should have higher PSNRs.
      * Also compares average and minimum PSNR of codec with PSNR values of reference Google codec.
      */
-    public void testEncoderQuality() throws Exception {
+    private void internalTestEncoderQuality(String codecMimeType) throws Exception {
         int encodeSeconds = 9;      // Encoding sequence duration in seconds for each bitrate.
         double[] psnrPlatformCodecAverage = new double[TEST_BITRATES_SET.length];
         double[] psnrPlatformCodecMin = new double[TEST_BITRATES_SET.length];
@@ -423,6 +429,7 @@
             EncoderOutputStreamParameters params = getDefaultEncodingParameters(
                     INPUT_YUV,
                     ENCODED_IVF_BASE,
+                    codecMimeType,
                     encodeSeconds,
                     WIDTH,
                     HEIGHT,
@@ -438,8 +445,8 @@
             completed[i] = true;
             skipped = false;
 
-            decode(params.outputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
-            Vp8DecodingStatistics statistics = computeDecodingStatistics(
+            decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+            VpxDecodingStatistics statistics = computeDecodingStatistics(
                     params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
                     params.frameWidth, params.frameHeight);
             psnrPlatformCodecAverage[i] = statistics.mAveragePSNR;
@@ -500,5 +507,32 @@
             }
         }
     }
+
+    public void testBasicVP8() throws Exception { internalTestBasic(VP8_MIME); }
+    public void testBasicVP9() throws Exception { internalTestBasic(VP9_MIME); }
+
+    public void testAsyncEncodingVP8() throws Exception { internalTestAsyncEncoding(VP8_MIME); }
+    public void testAsyncEncodingVP9() throws Exception { internalTestAsyncEncoding(VP9_MIME); }
+
+    public void testSyncFrameVP8() throws Exception { internalTestSyncFrame(VP8_MIME); }
+    public void testSyncFrameVP9() throws Exception { internalTestSyncFrame(VP9_MIME); }
+
+    public void testDynamicBitrateChangeVP8() throws Exception {
+        internalTestDynamicBitrateChange(VP8_MIME);
+    }
+    public void testDynamicBitrateChangeVP9() throws Exception {
+        internalTestDynamicBitrateChange(VP9_MIME);
+    }
+
+    public void testParallelEncodingAndDecodingVP8() throws Exception {
+        internalTestParallelEncodingAndDecoding(VP8_MIME);
+    }
+    public void testParallelEncodingAndDecodingVP9() throws Exception {
+        internalTestParallelEncodingAndDecoding(VP9_MIME);
+    }
+
+    public void testEncoderQualityVP8() throws Exception { internalTestEncoderQuality(VP8_MIME); }
+    public void testEncoderQualityVP9() throws Exception { internalTestEncoderQuality(VP9_MIME); }
+
 }
 
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index 5397fc6a..abbad8f 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_MULTILIB := both
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsdeviceutil ctstestrunner guava
+    android-support-test ctsdeviceutil ctstestrunner guava platform-test-annotations
 
 LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libctsos_jni libnativehelper_compat_libc++
 
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 4ebe527..3d8ab32 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -18,8 +18,8 @@
 */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android" coreApp="true" android:sharedUserId="android.uid.system"
-          android:sharedUserLabel="@string/android_system_label">
+    package="android" coreApp="true" android:sharedUserId="android.uid.system"
+    android:sharedUserLabel="@string/android_system_label">
 
     <!-- ================================================ -->
     <!-- Special broadcasts that only the system can send -->
@@ -138,49 +138,46 @@
     <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REPLY" />
     <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" />
     <protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" />
-    <protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" />
     <protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
     <protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
     <protected-broadcast
-            android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
+        android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED" />
+        android:name="android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
+        android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
     <protected-broadcast
-            android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
+        android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
+        android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
+        android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
     <protected-broadcast
-            android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
+        android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
+        android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
     <protected-broadcast
-            android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
+        android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
     <protected-broadcast
-            android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
+        android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
+        android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
+        android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
+        android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
+        android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
+        android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
+        android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
+        android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
     <protected-broadcast
-            android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
+        android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
     <protected-broadcast
-            android:name="android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED" />
-    <protected-broadcast
-            android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+        android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
     <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
     <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
@@ -192,7 +189,6 @@
     <protected-broadcast android:name="android.btopp.intent.action.RETRY" />
     <protected-broadcast android:name="android.btopp.intent.action.OPEN" />
     <protected-broadcast android:name="android.btopp.intent.action.OPEN_INBOUND" />
-    <protected-broadcast android:name="android.btopp.intent.action.TRANSFER_COMPLETE" />
     <protected-broadcast android:name="com.android.bluetooth.pbap.authchall" />
     <protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
     <protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
@@ -310,7 +306,7 @@
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
 
-    <protected-broadcast android:name="com.android.server.ACTION_TRIGGER_IDLE" />
+    <protected-broadcast android:name="com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE" />
 
     <protected-broadcast android:name="android.intent.action.HDMI_PLUGGED" />
 
@@ -330,11 +326,11 @@
     <protected-broadcast android:name="android.provider.Telephony.MMS_DOWNLOADED" />
 
     <protected-broadcast
-            android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
+        android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
 
     <!-- Defined in RestrictionsManager -->
     <protected-broadcast
-            android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
+        android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
     <!-- Defined in RestrictionsManager -->
 
     <protected-broadcast android:name="android.intent.action.REQUEST_PERMISSION" />
@@ -496,28 +492,28 @@
     <!-- Used for runtime permissions related to contacts and profiles on this
         device. -->
     <permission-group android:name="android.permission-group.CONTACTS"
-                      android:icon="@drawable/perm_group_contacts"
-                      android:label="@string/permgrouplab_contacts"
-                      android:description="@string/permgroupdesc_contacts"
-                      android:priority="100" />
+        android:icon="@drawable/perm_group_contacts"
+        android:label="@string/permgrouplab_contacts"
+        android:description="@string/permgroupdesc_contacts"
+        android:priority="100" />
 
     <!-- Allows an application to read the user's contacts data.
         <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_CONTACTS"
-                android:permissionGroup="android.permission-group.CONTACTS"
-                android:label="@string/permlab_readContacts"
-                android:description="@string/permdesc_readContacts"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.CONTACTS"
+        android:label="@string/permlab_readContacts"
+        android:description="@string/permdesc_readContacts"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write the user's contacts data.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.WRITE_CONTACTS"
-                android:permissionGroup="android.permission-group.CONTACTS"
-                android:label="@string/permlab_writeContacts"
-                android:description="@string/permdesc_writeContacts"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.CONTACTS"
+        android:label="@string/permlab_writeContacts"
+        android:description="@string/permdesc_writeContacts"
+        android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing user's calendar                              -->
@@ -526,28 +522,28 @@
 
     <!-- Used for runtime permissions related to user's calendar. -->
     <permission-group android:name="android.permission-group.CALENDAR"
-                      android:icon="@drawable/perm_group_calendar"
-                      android:label="@string/permgrouplab_calendar"
-                      android:description="@string/permgroupdesc_calendar"
-                      android:priority="200" />
+        android:icon="@drawable/perm_group_calendar"
+        android:label="@string/permgrouplab_calendar"
+        android:description="@string/permgroupdesc_calendar"
+        android:priority="200" />
 
     <!-- Allows an application to read the user's calendar data.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_CALENDAR"
-                android:permissionGroup="android.permission-group.CALENDAR"
-                android:label="@string/permlab_readCalendar"
-                android:description="@string/permdesc_readCalendar"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.CALENDAR"
+        android:label="@string/permlab_readCalendar"
+        android:description="@string/permdesc_readCalendar"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write the user's calendar data.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.WRITE_CALENDAR"
-                android:permissionGroup="android.permission-group.CALENDAR"
-                android:label="@string/permlab_writeCalendar"
-                android:description="@string/permdesc_writeCalendar"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.CALENDAR"
+        android:label="@string/permlab_writeCalendar"
+        android:description="@string/permdesc_writeCalendar"
+        android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing and modifying user's SMS messages            -->
@@ -556,56 +552,56 @@
 
     <!-- Used for runtime permissions related to user's SMS messages. -->
     <permission-group android:name="android.permission-group.SMS"
-                      android:icon="@drawable/perm_group_sms"
-                      android:label="@string/permgrouplab_sms"
-                      android:description="@string/permgroupdesc_sms"
-                      android:priority="300" />
+        android:icon="@drawable/perm_group_sms"
+        android:label="@string/permgrouplab_sms"
+        android:description="@string/permgroupdesc_sms"
+        android:priority="300" />
 
     <!-- Allows an application to send SMS messages.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.SEND_SMS"
-                android:permissionGroup="android.permission-group.SMS"
-                android:label="@string/permlab_sendSms"
-                android:description="@string/permdesc_sendSms"
-                android:permissionFlags="costsMoney"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.SMS"
+        android:label="@string/permlab_sendSms"
+        android:description="@string/permdesc_sendSms"
+        android:permissionFlags="costsMoney"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to receive SMS messages.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.RECEIVE_SMS"
-                android:permissionGroup="android.permission-group.SMS"
-                android:label="@string/permlab_receiveSms"
-                android:description="@string/permdesc_receiveSms"
-                android:protectionLevel="dangerous"/>
+        android:permissionGroup="android.permission-group.SMS"
+        android:label="@string/permlab_receiveSms"
+        android:description="@string/permdesc_receiveSms"
+        android:protectionLevel="dangerous"/>
 
     <!-- Allows an application to read SMS messages.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_SMS"
-                android:permissionGroup="android.permission-group.SMS"
-                android:label="@string/permlab_readSms"
-                android:description="@string/permdesc_readSms"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.SMS"
+        android:label="@string/permlab_readSms"
+        android:description="@string/permdesc_readSms"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to receive WAP push messages.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.RECEIVE_WAP_PUSH"
-                android:permissionGroup="android.permission-group.SMS"
-                android:label="@string/permlab_receiveWapPush"
-                android:description="@string/permdesc_receiveWapPush"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.SMS"
+        android:label="@string/permlab_receiveWapPush"
+        android:description="@string/permdesc_receiveWapPush"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to monitor incoming MMS messages.
         <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.RECEIVE_MMS"
-                android:permissionGroup="android.permission-group.SMS"
-                android:label="@string/permlab_receiveMms"
-                android:description="@string/permdesc_receiveMms"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.SMS"
+        android:label="@string/permlab_receiveMms"
+        android:description="@string/permdesc_receiveMms"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to read previously received cell broadcast
          messages and to register a content observer to get notifications when
@@ -620,10 +616,10 @@
          <p>Protection level: dangerous
          @hide Pending API council approval -->
     <permission android:name="android.permission.READ_CELL_BROADCASTS"
-                android:permissionGroup="android.permission-group.SMS"
-                android:label="@string/permlab_readCellBroadcasts"
-                android:description="@string/permdesc_readCellBroadcasts"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.SMS"
+        android:label="@string/permlab_readCellBroadcasts"
+        android:description="@string/permdesc_readCellBroadcasts"
+        android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing external storage                             -->
@@ -632,10 +628,10 @@
 
     <!-- Used for runtime permissions related to the shared external storage. -->
     <permission-group android:name="android.permission-group.STORAGE"
-                      android:icon="@drawable/perm_group_storage"
-                      android:label="@string/permgrouplab_storage"
-                      android:description="@string/permgroupdesc_storage"
-                      android:priority="900" />
+        android:icon="@drawable/perm_group_storage"
+        android:label="@string/permgrouplab_storage"
+        android:description="@string/permgroupdesc_storage"
+        android:priority="900" />
 
     <!-- Allows an application to read from external storage.
      <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
@@ -660,10 +656,10 @@
      <p>Protection level: dangerous
      -->
     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
-                android:permissionGroup="android.permission-group.STORAGE"
-                android:label="@string/permlab_sdcardRead"
-                android:description="@string/permdesc_sdcardRead"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.STORAGE"
+        android:label="@string/permlab_sdcardRead"
+        android:description="@string/permdesc_sdcardRead"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write to external storage.
          <p class="note"><strong>Note:</strong> If <em>both</em> your <a
@@ -681,10 +677,10 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
-                android:permissionGroup="android.permission-group.STORAGE"
-                android:label="@string/permlab_sdcardWrite"
-                android:description="@string/permdesc_sdcardWrite"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.STORAGE"
+        android:label="@string/permlab_sdcardWrite"
+        android:description="@string/permdesc_sdcardWrite"
+        android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device location                          -->
@@ -693,28 +689,28 @@
 
     <!-- Used for permissions that allow accessing the device location. -->
     <permission-group android:name="android.permission-group.LOCATION"
-                      android:icon="@drawable/perm_group_location"
-                      android:label="@string/permgrouplab_location"
-                      android:description="@string/permgroupdesc_location"
-                      android:priority="400" />
+        android:icon="@drawable/perm_group_location"
+        android:label="@string/permgrouplab_location"
+        android:description="@string/permgroupdesc_location"
+        android:priority="400" />
 
     <!-- Allows an app to access precise location.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACCESS_FINE_LOCATION"
-                android:permissionGroup="android.permission-group.LOCATION"
-                android:label="@string/permlab_accessFineLocation"
-                android:description="@string/permdesc_accessFineLocation"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.LOCATION"
+        android:label="@string/permlab_accessFineLocation"
+        android:description="@string/permdesc_accessFineLocation"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an app to access approximate location.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACCESS_COARSE_LOCATION"
-                android:permissionGroup="android.permission-group.LOCATION"
-                android:label="@string/permlab_accessCoarseLocation"
-                android:description="@string/permdesc_accessCoarseLocation"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.LOCATION"
+        android:label="@string/permlab_accessCoarseLocation"
+        android:description="@string/permdesc_accessCoarseLocation"
+        android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device telephony                         -->
@@ -723,10 +719,10 @@
 
     <!-- Used for permissions that are associated telephony features. -->
     <permission-group android:name="android.permission-group.PHONE"
-                      android:icon="@drawable/perm_group_phone_calls"
-                      android:label="@string/permgrouplab_phone"
-                      android:description="@string/permgroupdesc_phone"
-                      android:priority="500" />
+        android:icon="@drawable/perm_group_phone_calls"
+        android:label="@string/permgrouplab_phone"
+        android:description="@string/permgroupdesc_phone"
+        android:priority="500" />
 
     <!-- Allows read only access to phone state, including the phone number of the device,
          current cellular network information, the status of any ongoing calls, and a list of any
@@ -742,21 +738,21 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_PHONE_STATE"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:label="@string/permlab_readPhoneState"
-                android:description="@string/permdesc_readPhoneState"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_readPhoneState"
+        android:description="@string/permdesc_readPhoneState"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to initiate a phone call without going through
         the Dialer user interface for the user to confirm the call.
         <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.CALL_PHONE"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:permissionFlags="costsMoney"
-                android:label="@string/permlab_callPhone"
-                android:description="@string/permdesc_callPhone"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.PHONE"
+        android:permissionFlags="costsMoney"
+        android:label="@string/permlab_callPhone"
+        android:description="@string/permdesc_callPhone"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to access the IMS call service: making and
          modifying a call
@@ -764,10 +760,10 @@
         @hide
     -->
     <permission android:name="android.permission.ACCESS_IMS_CALL_SERVICE"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:label="@string/permlab_accessImsCallService"
-                android:description="@string/permdesc_accessImsCallService"
-                android:protectionLevel="signature|privileged" />
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_accessImsCallService"
+        android:description="@string/permdesc_accessImsCallService"
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to read the user's call log.
          <p class="note"><strong>Note:</strong> If your app uses the
@@ -782,10 +778,10 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_CALL_LOG"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:label="@string/permlab_readCallLog"
-                android:description="@string/permdesc_readCallLog"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_readCallLog"
+        android:description="@string/permdesc_readCallLog"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write (but not read) the user's
          call log data.
@@ -801,28 +797,28 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.WRITE_CALL_LOG"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:label="@string/permlab_writeCallLog"
-                android:description="@string/permdesc_writeCallLog"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_writeCallLog"
+        android:description="@string/permdesc_writeCallLog"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to add voicemails into the system.
          <p>Protection level: dangerous
     -->
     <permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:label="@string/permlab_addVoicemail"
-                android:description="@string/permdesc_addVoicemail"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_addVoicemail"
+        android:description="@string/permdesc_addVoicemail"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to use SIP service.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.USE_SIP"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:description="@string/permdesc_use_sip"
-                android:label="@string/permlab_use_sip"
-                android:protectionLevel="dangerous"/>
+        android:permissionGroup="android.permission-group.PHONE"
+        android:description="@string/permdesc_use_sip"
+        android:label="@string/permlab_use_sip"
+        android:protectionLevel="dangerous"/>
 
     <!-- Allows an application to see the number being dialed during an outgoing
          call with the option to redirect the call to a different number or
@@ -830,10 +826,10 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:label="@string/permlab_processOutgoingCalls"
-                android:description="@string/permdesc_processOutgoingCalls"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_processOutgoingCalls"
+        android:description="@string/permdesc_processOutgoingCalls"
+        android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device microphone                        -->
@@ -844,19 +840,19 @@
          microphone audio from the device. Note that phone calls also capture audio
          but are in a separate (more visible) permission group. -->
     <permission-group android:name="android.permission-group.MICROPHONE"
-                      android:icon="@drawable/perm_group_microphone"
-                      android:label="@string/permgrouplab_microphone"
-                      android:description="@string/permgroupdesc_microphone"
-                      android:priority="600" />
+        android:icon="@drawable/perm_group_microphone"
+        android:label="@string/permgrouplab_microphone"
+        android:description="@string/permgroupdesc_microphone"
+        android:priority="600" />
 
     <!-- Allows an application to record audio.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.RECORD_AUDIO"
-                android:permissionGroup="android.permission-group.MICROPHONE"
-                android:label="@string/permlab_recordAudio"
-                android:description="@string/permdesc_recordAudio"
-                android:protectionLevel="dangerous"/>
+        android:permissionGroup="android.permission-group.MICROPHONE"
+        android:label="@string/permlab_recordAudio"
+        android:description="@string/permdesc_recordAudio"
+        android:protectionLevel="dangerous"/>
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the UCE Service                              -->
@@ -866,15 +862,15 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:protectionLevel="signatureOrSystem"/>
+        android:permissionGroup="android.permission-group.PHONE"
+        android:protectionLevel="signatureOrSystem"/>
 
     <!-- @hide Allows an application to Access UCE-OPTIONS.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
-                android:permissionGroup="android.permission-group.PHONE"
-                android:protectionLevel="signatureOrSystem"/>
+        android:permissionGroup="android.permission-group.PHONE"
+        android:protectionLevel="signatureOrSystem"/>
 
 
 
@@ -886,10 +882,10 @@
     <!-- Used for permissions that are associated with accessing
      camera or capturing images/video from the device. -->
     <permission-group android:name="android.permission-group.CAMERA"
-                      android:icon="@drawable/perm_group_camera"
-                      android:label="@string/permgrouplab_camera"
-                      android:description="@string/permgroupdesc_camera"
-                      android:priority="700" />
+        android:icon="@drawable/perm_group_camera"
+        android:label="@string/permgrouplab_camera"
+        android:description="@string/permgroupdesc_camera"
+        android:priority="700" />
 
     <!-- Required to be able to access the camera device.
          <p>This will automatically enforce the <a
@@ -901,10 +897,10 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.CAMERA"
-                android:permissionGroup="android.permission-group.CAMERA"
-                android:label="@string/permlab_camera"
-                android:description="@string/permdesc_camera"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.CAMERA"
+        android:label="@string/permlab_camera"
+        android:description="@string/permdesc_camera"
+        android:protectionLevel="dangerous" />
 
 
     <!-- ====================================================================== -->
@@ -915,28 +911,28 @@
     <!-- Used for permissions that are associated with accessing
          camera or capturing images/video from the device. -->
     <permission-group android:name="android.permission-group.SENSORS"
-                      android:icon="@drawable/perm_group_sensors"
-                      android:label="@string/permgrouplab_sensors"
-                      android:description="@string/permgroupdesc_sensors"
-                      android:priority="800" />
+        android:icon="@drawable/perm_group_sensors"
+        android:label="@string/permgrouplab_sensors"
+        android:description="@string/permgroupdesc_sensors"
+        android:priority="800" />
 
     <!-- Allows an application to access data from sensors that the user uses to
          measure what is happening inside his/her body, such as heart rate.
          <p>Protection level: dangerous -->
     <permission android:name="android.permission.BODY_SENSORS"
-                android:permissionGroup="android.permission-group.SENSORS"
-                android:label="@string/permlab_bodySensors"
-                android:description="@string/permdesc_bodySensors"
-                android:protectionLevel="dangerous" />
+        android:permissionGroup="android.permission-group.SENSORS"
+        android:label="@string/permlab_bodySensors"
+        android:description="@string/permdesc_bodySensors"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an app to use fingerprint hardware.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.USE_FINGERPRINT"
-                android:permissionGroup="android.permission-group.SENSORS"
-                android:label="@string/permlab_useFingerprint"
-                android:description="@string/permdesc_useFingerprint"
-                android:protectionLevel="normal" />
+        android:permissionGroup="android.permission-group.SENSORS"
+        android:label="@string/permlab_useFingerprint"
+        android:description="@string/permdesc_useFingerprint"
+        android:protectionLevel="normal" />
 
     <!-- ====================================================================== -->
     <!-- REMOVED PERMISSIONS                                                    -->
@@ -944,78 +940,78 @@
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.READ_PROFILE"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.WRITE_PROFILE"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.READ_SOCIAL_STREAM"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.WRITE_SOCIAL_STREAM"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.READ_USER_DICTIONARY"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.WRITE_USER_DICTIONARY"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.WRITE_SMS"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.MANAGE_ACCOUNTS"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.USE_CREDENTIALS"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- @hide We need to keep this around for backwards compatibility -->
     <permission android:name="android.permission.FLASHLIGHT"
-                android:protectionLevel="normal"
-                android:permissionFlags="removed"/>
+        android:protectionLevel="normal"
+        android:permissionFlags="removed"/>
 
     <!-- ====================================================================== -->
     <!-- INSTALL PERMISSIONS                                                    -->
@@ -1030,37 +1026,35 @@
          to handle the respond-via-message action during incoming calls.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to send SMS to premium shortcodes without user permission.
-         <p>Not for use by third-party applications.
-         @hide -->
+         <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SEND_SMS_NO_CONFIRMATION"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to filter carrier specific sms.
          @hide -->
     <permission android:name="android.permission.CARRIER_FILTER_SMS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to receive emergency cell broadcast messages,
          to record or display them to the user.
-         <p>Not for use by third-party applications.
-         @hide -->
+         <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to monitor incoming Bluetooth MAP messages, to record
          or perform processing on them. -->
     <!-- @hide -->
     <permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allows an application to execute contacts directory search.
          This should only be used by ContactsProvider.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BIND_DIRECTORY_SEARCH"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allows an application to modify cell broadcasts through the content provider.
          <p>Not for use by third-party applications. -->
@@ -1076,9 +1070,9 @@
          <p>Protection level: normal
     -->
     <permission android:name="com.android.alarm.permission.SET_ALARM"
-                android:label="@string/permlab_setAlarm"
-                android:description="@string/permdesc_setAlarm"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_setAlarm"
+        android:description="@string/permdesc_setAlarm"
+        android:protectionLevel="normal" />
 
     <!-- =============================================================== -->
     <!-- Permissions for accessing the user voicemail                    -->
@@ -1089,13 +1083,13 @@
         <p>Protection level: signature|privileged
     -->
     <permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to read voicemails in the system.
          <p>Protection level: signature|privileged
     -->
     <permission android:name="com.android.voicemail.permission.READ_VOICEMAIL"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- ======================================= -->
     <!-- Permissions for accessing location info -->
@@ -1106,26 +1100,26 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"
-                android:label="@string/permlab_accessLocationExtraCommands"
-                android:description="@string/permdesc_accessLocationExtraCommands"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_accessLocationExtraCommands"
+        android:description="@string/permdesc_accessLocationExtraCommands"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows an application to install a location provider into the Location Manager.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
          This should only be used by HDMI-CEC service.
     -->
     <permission android:name="android.permission.HDMI_CEC"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to use location features in hardware,
          such as the geofencing api.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.LOCATION_HARDWARE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
     <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
 
     <!-- @SystemApi Allows an application to create mock location providers for testing.
@@ -1133,7 +1127,7 @@
          @hide
     -->
     <permission android:name="android.permission.ACCESS_MOCK_LOCATION"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- ======================================= -->
     <!-- Permissions for accessing networks -->
@@ -1144,73 +1138,73 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.INTERNET"
-                android:description="@string/permdesc_createNetworkSockets"
-                android:label="@string/permlab_createNetworkSockets"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_createNetworkSockets"
+        android:label="@string/permlab_createNetworkSockets"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to access information about networks.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.ACCESS_NETWORK_STATE"
-                android:description="@string/permdesc_accessNetworkState"
-                android:label="@string/permlab_accessNetworkState"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_accessNetworkState"
+        android:label="@string/permlab_accessNetworkState"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to access information about Wi-Fi networks.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.ACCESS_WIFI_STATE"
-                android:description="@string/permdesc_accessWifiState"
-                android:label="@string/permlab_accessWifiState"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_accessWifiState"
+        android:label="@string/permlab_accessWifiState"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to change Wi-Fi connectivity state.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.CHANGE_WIFI_STATE"
-                android:description="@string/permdesc_changeWifiState"
-                android:label="@string/permlab_changeWifiState"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_changeWifiState"
+        android:label="@string/permlab_changeWifiState"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allows applications to change tether state and run
          tether carrier provisioning.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.TETHER_PRIVILEGED"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allow system apps to receive broadcast
          when a wifi network credential is changed.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allows an application to modify any wifi configuration, even if created
      by another application. Once reconfigured the original creator cannot make any further
      modifications.
      <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @hide -->
     <permission android:name="android.permission.ACCESS_WIMAX_STATE"
-                android:description="@string/permdesc_accessWimaxState"
-                android:label="@string/permlab_accessWimaxState"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_accessWimaxState"
+        android:label="@string/permlab_accessWimaxState"
+        android:protectionLevel="normal" />
 
     <!-- @hide -->
     <permission android:name="android.permission.CHANGE_WIMAX_STATE"
-                android:description="@string/permdesc_changeWimaxState"
-                android:label="@string/permlab_changeWimaxState"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_changeWimaxState"
+        android:label="@string/permlab_changeWimaxState"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to act as network scorers. @hide @SystemApi-->
     <permission android:name="android.permission.SCORE_NETWORKS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
@@ -1221,68 +1215,68 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.BLUETOOTH"
-                android:description="@string/permdesc_bluetooth"
-                android:label="@string/permlab_bluetooth"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_bluetooth"
+        android:label="@string/permlab_bluetooth"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to discover and pair bluetooth devices.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.BLUETOOTH_ADMIN"
-                android:description="@string/permdesc_bluetoothAdmin"
-                android:label="@string/permlab_bluetoothAdmin"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_bluetoothAdmin"
+        android:label="@string/permlab_bluetoothAdmin"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows applications to pair bluetooth devices without user interaction, and to
          allow or disallow phonebook access or message access.
          This is not available to third party applications. -->
     <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Control access to email providers exclusively for Bluetooth
          @hide
     -->
     <permission android:name="android.permission.BLUETOOTH_MAP"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows bluetooth stack to access files
          @hide This should only be used by Bluetooth apk.
     -->
     <permission android:name="android.permission.BLUETOOTH_STACK"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows applications to perform I/O operations over NFC.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.NFC"
-                android:description="@string/permdesc_nfc"
-                android:label="@string/permlab_nfc"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_nfc"
+        android:label="@string/permlab_nfc"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
          @hide -->
     <permission android:name="android.permission.CONNECTIVITY_INTERNAL"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows a system application to access hardware packet offload capabilities.
          @hide -->
     <permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi
          @hide -->
     <permission android:name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows access to the loop radio (Android@Home mesh network) device.
          @hide -->
     <permission android:name="android.permission.LOOP_RADIO"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows sending and receiving handover transfer status from Wifi and Bluetooth
          @hide -->
     <permission android:name="android.permission.NFC_HANDOVER_STATUS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
@@ -1301,15 +1295,15 @@
     <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.GET_ACCOUNTS"
-                android:permissionGroup="android.permission-group.CONTACTS"
-                android:protectionLevel="dangerous"
-                android:description="@string/permdesc_getAccounts"
-                android:label="@string/permlab_getAccounts" />
+        android:permissionGroup="android.permission-group.CONTACTS"
+        android:protectionLevel="dangerous"
+        android:description="@string/permdesc_getAccounts"
+        android:label="@string/permlab_getAccounts" />
 
     <!-- @SystemApi Allows applications to call into AccountAuthenticators.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.ACCOUNT_MANAGER"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- ================================== -->
     <!-- Permissions for accessing hardware that may effect battery life-->
@@ -1320,34 +1314,34 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
-                android:description="@string/permdesc_changeWifiMulticastState"
-                android:label="@string/permlab_changeWifiMulticastState"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_changeWifiMulticastState"
+        android:label="@string/permlab_changeWifiMulticastState"
+        android:protectionLevel="normal" />
 
     <!-- Allows access to the vibrator.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.VIBRATE"
-                android:label="@string/permlab_vibrate"
-                android:description="@string/permdesc_vibrate"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_vibrate"
+        android:description="@string/permdesc_vibrate"
+        android:protectionLevel="normal" />
 
     <!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
          from dimming.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.WAKE_LOCK"
-                android:label="@string/permlab_wakeLock"
-                android:description="@string/permdesc_wakeLock"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_wakeLock"
+        android:description="@string/permdesc_wakeLock"
+        android:protectionLevel="normal" />
 
     <!-- Allows using the device's IR transmitter, if available.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.TRANSMIT_IR"
-                android:label="@string/permlab_transmitIr"
-                android:description="@string/permdesc_transmitIr"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_transmitIr"
+        android:description="@string/permdesc_transmitIr"
+        android:protectionLevel="normal" />
 
     <!-- ==================================================== -->
     <!-- Permissions related to changing audio settings   -->
@@ -1358,9 +1352,9 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"
-                android:label="@string/permlab_modifyAudioSettings"
-                android:description="@string/permdesc_modifyAudioSettings"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_modifyAudioSettings"
+        android:description="@string/permdesc_modifyAudioSettings"
+        android:protectionLevel="normal" />
 
     <!-- ================================== -->
     <!-- Permissions for accessing hardware -->
@@ -1370,53 +1364,53 @@
     <!-- @SystemApi Allows an application to manage preferences and permissions for USB devices
          @hide -->
     <permission android:name="android.permission.MANAGE_USB"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to access the MTP USB kernel driver.
          For use only by the device side MTP implementation.
          @hide -->
     <permission android:name="android.permission.ACCESS_MTP"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows access to hardware peripherals.  Intended only for hardware testing.
          <p>Not for use by third-party applications.
          @hide
     -->
     <permission android:name="android.permission.HARDWARE_TEST"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows access to FM
          @hide This is not a third-party API (intended for system apps).-->
     <permission android:name="android.permission.ACCESS_FM_RADIO"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows access to configure network interfaces, configure/use IPSec, etc.
          @hide -->
     <permission android:name="android.permission.NET_ADMIN"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows registration for remote audio playback. @hide -->
     <permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows TvInputService to access underlying TV input hardware such as
          built-in tuners and HDMI-in's.
          @hide This should only be used by OEM's TvInputService's.
     -->
     <permission android:name="android.permission.TV_INPUT_HARDWARE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows to capture a frame of TV input hardware such as
          built-in tuners and HDMI-in's.
          @hide <p>Not for use by third-party applications.
     -->
     <permission android:name="android.permission.CAPTURE_TV_INPUT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @hide Allows TvInputService to access DVB device.
    <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DVB_DEVICE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows reading the OEM unlock state
          @hide <p>Not for use by third-party applications. -->
@@ -1426,17 +1420,17 @@
     <!-- @hide Allows enabling/disabling OEM unlock
    <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.OEM_UNLOCK_STATE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Allows querying state of PersistentDataBlock
    <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.ACCESS_PDB_STATE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Allows system update service to notify device owner about pending updates.
    <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.NOTIFY_PENDING_SYSTEM_UPDATE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- =========================================== -->
     <!-- Permissions associated with camera and image capture -->
@@ -1447,12 +1441,12 @@
          a camera is in use by an application.
          @hide -->
     <permission android:name="android.permission.CAMERA_DISABLE_TRANSMIT_LED"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows sending the camera service notifications about system-wide events.
         @hide -->
     <permission android:name="android.permission.CAMERA_SEND_SYSTEM_EVENTS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- =========================================== -->
     <!-- Permissions associated with telephony state -->
@@ -1463,50 +1457,50 @@
          Does not include placing calls.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MODIFY_PHONE_STATE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows read only access to precise phone state.
          @hide Pending API council approval -->
     <permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows read access to privileged phone state.
          @hide Used internally. -->
     <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
          corresponds to a device SIM.
          @hide -->
     <permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_CALL_PROVIDER.
          @hide -->
     <permission android:name="android.permission.REGISTER_CALL_PROVIDER"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_CONNECTION_MANAGER
          @hide -->
     <permission android:name="android.permission.REGISTER_CONNECTION_MANAGER"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.telecom.InCallService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_INCALL_SERVICE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.telecom.CallScreeningService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_SCREENING_SERVICE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.telecom.ConnectionService},
          to ensure that only the system can bind to it.
@@ -1515,24 +1509,24 @@
          @SystemApi
          @hide -->
     <permission android:name="android.permission.BIND_CONNECTION_SERVICE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.telecom.ConnectionService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to control the in-call experience.
          @hide -->
     <permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to receive STK related commands.
          @hide -->
     <permission android:name="android.permission.RECEIVE_STK_COMMANDS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
@@ -1542,7 +1536,7 @@
     <!-- @SystemApi Allows an application to write to internal media storage
          @hide  -->
     <permission android:name="android.permission.WRITE_MEDIA_STORAGE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to manage access to documents, usually as part
          of a document picker.
@@ -1552,14 +1546,14 @@
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to cache content.
          <p>Not for use by third-party applications.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.CACHE_CONTENT"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- ================================== -->
     <!-- Permissions for screenlock         -->
@@ -1570,9 +1564,9 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.DISABLE_KEYGUARD"
-                android:description="@string/permdesc_disableKeyguard"
-                android:label="@string/permlab_disableKeyguard"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_disableKeyguard"
+        android:label="@string/permlab_disableKeyguard"
+        android:protectionLevel="normal" />
 
     <!-- ================================== -->
     <!-- Permissions to access other installed applications  -->
@@ -1581,9 +1575,9 @@
 
     <!-- @deprecated No longer enforced. -->
     <permission android:name="android.permission.GET_TASKS"
-                android:label="@string/permlab_getTasks"
-                android:description="@string/permdesc_getTasks"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_getTasks"
+        android:description="@string/permdesc_getTasks"
+        android:protectionLevel="normal" />
 
     <!-- New version of GET_TASKS that apps can request, since GET_TASKS doesn't really
          give access to task information.  We need this new one because there are
@@ -1596,32 +1590,32 @@
          @hide
          @SystemApi -->
     <permission android:name="android.permission.REAL_GET_TASKS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to start a task from a ActivityManager#RecentTaskInfo.
          @hide -->
     <permission android:name="android.permission.START_TASKS_FROM_RECENTS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allows an application to call APIs that allow it to do interactions
          across the users on the device, using singleton services and
          user-targeted broadcasts.  This permission is not available to
          third party applications. -->
     <permission android:name="android.permission.INTERACT_ACROSS_USERS"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
          that removes restrictions on where broadcasts can be sent and allows other
          types of interactions
          @hide -->
     <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
-                android:protectionLevel="signature|installer" />
+        android:protectionLevel="signature|installer" />
 
     <!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
          users on the device. This permission is not available to
          third party applications. -->
     <permission android:name="android.permission.MANAGE_USERS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @hide Allows an application to create, remove users and get the list of
          users on the device. Applications holding this permission can only create restricted,
@@ -1634,69 +1628,69 @@
     <!-- @hide Allows an application to set the profile owners and the device owner.
          This permission is not available to third party applications.-->
     <permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
-                android:protectionLevel="signature"
-                android:label="@string/permlab_manageProfileAndDeviceOwners"
-                android:description="@string/permdesc_manageProfileAndDeviceOwners" />
+        android:protectionLevel="signature"
+        android:label="@string/permlab_manageProfileAndDeviceOwners"
+        android:description="@string/permdesc_manageProfileAndDeviceOwners" />
 
     <!-- Allows an application to get full detailed information about
          recently running tasks, with full fidelity to the real state.
          @hide -->
     <permission android:name="android.permission.GET_DETAILED_TASKS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to change the Z-order of tasks.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.REORDER_TASKS"
-                android:label="@string/permlab_reorderTasks"
-                android:description="@string/permdesc_reorderTasks"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_reorderTasks"
+        android:description="@string/permdesc_reorderTasks"
+        android:protectionLevel="normal" />
 
     <!-- @hide Allows an application to change to remove/kill tasks -->
     <permission android:name="android.permission.REMOVE_TASKS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi @hide Allows an application to create/manage/remove stacks -->
     <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to start any activity, regardless of permission
          protection or exported state.
          @hide -->
     <permission android:name="android.permission.START_ANY_ACTIVITY"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
         API is no longer supported. -->
     <permission android:name="android.permission.RESTART_PACKAGES"
-                android:label="@string/permlab_killBackgroundProcesses"
-                android:description="@string/permdesc_killBackgroundProcesses"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_killBackgroundProcesses"
+        android:description="@string/permdesc_killBackgroundProcesses"
+        android:protectionLevel="normal" />
 
     <!-- Allows an application to call
         {@link android.app.ActivityManager#killBackgroundProcesses}.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
-                android:label="@string/permlab_killBackgroundProcesses"
-                android:description="@string/permdesc_killBackgroundProcesses"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_killBackgroundProcesses"
+        android:description="@string/permdesc_killBackgroundProcesses"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi @hide Allows an application to query process states and current
          OOM adjustment scores.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi @hide Allows an application to retrieve a package's importance.
          This permission is not available to third party applications. -->
     <permission android:name="android.permission.GET_PACKAGE_IMPORTANCE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows use of PendingIntent.getIntent().
          @hide -->
     <permission android:name="android.permission.GET_INTENT_SENDER_INTENT"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- ================================== -->
     <!-- Permissions affecting the display of other applications  -->
@@ -1719,9 +1713,9 @@
          Settings.canDrawOverlays()}.
          <p>Protection level: signature -->
     <permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
-                android:label="@string/permlab_systemAlertWindow"
-                android:description="@string/permdesc_systemAlertWindow"
-                android:protectionLevel="signature|preinstalled|appop|pre23|development" />
+        android:label="@string/permlab_systemAlertWindow"
+        android:description="@string/permdesc_systemAlertWindow"
+        android:protectionLevel="signature|preinstalled|appop|pre23|development" />
 
     <!-- ================================== -->
     <!-- Permissions affecting the system wallpaper -->
@@ -1732,17 +1726,17 @@
          <p>Protection level: normal
      -->
     <permission android:name="android.permission.SET_WALLPAPER"
-                android:label="@string/permlab_setWallpaper"
-                android:description="@string/permdesc_setWallpaper"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_setWallpaper"
+        android:description="@string/permdesc_setWallpaper"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to set the wallpaper hints.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.SET_WALLPAPER_HINTS"
-                android:label="@string/permlab_setWallpaperHints"
-                android:description="@string/permdesc_setWallpaperHints"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_setWallpaperHints"
+        android:description="@string/permdesc_setWallpaperHints"
+        android:protectionLevel="normal" />
 
     <!-- ============================================ -->
     <!-- Permissions for changing the system clock -->
@@ -1752,15 +1746,15 @@
     <!-- @SystemApi Allows applications to set the system time.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_TIME"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows applications to set the system time zone.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.SET_TIME_ZONE"
-                android:label="@string/permlab_setTimeZone"
-                android:description="@string/permdesc_setTimeZone"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_setTimeZone"
+        android:description="@string/permdesc_setTimeZone"
+        android:protectionLevel="normal" />
 
     <!-- ==================================================== -->
     <!-- Permissions related to changing status bar   -->
@@ -1771,9 +1765,9 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.EXPAND_STATUS_BAR"
-                android:label="@string/permlab_expandStatusBar"
-                android:description="@string/permdesc_expandStatusBar"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_expandStatusBar"
+        android:description="@string/permdesc_expandStatusBar"
+        android:protectionLevel="normal" />
 
     <!-- ============================================================== -->
     <!-- Permissions related to adding/removing shortcuts from Launcher -->
@@ -1784,17 +1778,17 @@
          <p>Protection level: normal
     -->
     <permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
-                android:label="@string/permlab_install_shortcut"
-                android:description="@string/permdesc_install_shortcut"
-                android:protectionLevel="normal"/>
+        android:label="@string/permlab_install_shortcut"
+        android:description="@string/permdesc_install_shortcut"
+        android:protectionLevel="normal"/>
 
     <!-- Allows an application to uninstall a shortcut in Launcher.
          <p>Protection level: normal
     -->
     <permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
-                android:label="@string/permlab_uninstall_shortcut"
-                android:description="@string/permdesc_uninstall_shortcut"
-                android:protectionLevel="normal"/>
+        android:label="@string/permlab_uninstall_shortcut"
+        android:description="@string/permdesc_uninstall_shortcut"
+        android:protectionLevel="normal"/>
 
     <!-- ==================================================== -->
     <!-- Permissions related to accessing sync settings   -->
@@ -1805,25 +1799,25 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.READ_SYNC_SETTINGS"
-                android:description="@string/permdesc_readSyncSettings"
-                android:label="@string/permlab_readSyncSettings"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_readSyncSettings"
+        android:label="@string/permlab_readSyncSettings"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to write the sync settings.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.WRITE_SYNC_SETTINGS"
-                android:description="@string/permdesc_writeSyncSettings"
-                android:label="@string/permlab_writeSyncSettings"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_writeSyncSettings"
+        android:label="@string/permlab_writeSyncSettings"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to read the sync stats.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.READ_SYNC_STATS"
-                android:description="@string/permdesc_readSyncStats"
-                android:label="@string/permlab_readSyncStats"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_readSyncStats"
+        android:label="@string/permlab_readSyncStats"
+        android:protectionLevel="normal" />
 
     <!-- ============================================ -->
     <!-- Permissions for low-level system interaction -->
@@ -1832,12 +1826,12 @@
 
     <!-- @SystemApi @hide Change the screen compatibility mode of applications -->
     <permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to modify the current configuration, such
          as locale. -->
     <permission android:name="android.permission.CHANGE_CONFIGURATION"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- Allows an application to read or write the system settings.
 
@@ -1852,51 +1846,51 @@
         <p>Protection level: signature
     -->
     <permission android:name="android.permission.WRITE_SETTINGS"
-                android:label="@string/permlab_writeSettings"
-                android:description="@string/permdesc_writeSettings"
-                android:protectionLevel="signature|preinstalled|appop|pre23" />
+        android:label="@string/permlab_writeSettings"
+        android:description="@string/permdesc_writeSettings"
+        android:protectionLevel="signature|preinstalled|appop|pre23" />
 
     <!-- @SystemApi Allows an application to modify the Google service map.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WRITE_GSERVICES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to call
         {@link android.app.ActivityManager#forceStopPackage}.
         @hide -->
     <permission android:name="android.permission.FORCE_STOP_PACKAGES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allows an application to retrieve the content of the active window
          An active window is the window that has fired an accessibility event. -->
     <permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Modify the global animation scaling factor.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_ANIMATION_SCALE"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @deprecated This functionality will be removed in the future; please do
          not use. Allow an application to make its activities persistent. -->
     <permission android:name="android.permission.PERSISTENT_ACTIVITY"
-                android:label="@string/permlab_persistentActivity"
-                android:description="@string/permdesc_persistentActivity"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_persistentActivity"
+        android:description="@string/permdesc_persistentActivity"
+        android:protectionLevel="normal" />
 
     <!-- Allows an application to find out the space used by any package.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.GET_PACKAGE_SIZE"
-                android:label="@string/permlab_getPackageSize"
-                android:description="@string/permdesc_getPackageSize"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_getPackageSize"
+        android:description="@string/permdesc_getPackageSize"
+        android:protectionLevel="normal" />
 
     <!-- @deprecated No longer useful, see
          {@link android.content.pm.PackageManager#addPackageToPreferred}
          for details. -->
     <permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to receive the
          {@link android.content.Intent#ACTION_BOOT_COMPLETED} that is
@@ -1912,9 +1906,9 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
-                android:label="@string/permlab_receiveBootCompleted"
-                android:description="@string/permdesc_receiveBootCompleted"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_receiveBootCompleted"
+        android:description="@string/permdesc_receiveBootCompleted"
+        android:protectionLevel="normal" />
 
     <!-- Allows an application to broadcast sticky intents.  These are
          broadcasts whose data is held by the system after being finished,
@@ -1923,90 +1917,90 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.BROADCAST_STICKY"
-                android:label="@string/permlab_broadcastSticky"
-                android:description="@string/permdesc_broadcastSticky"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_broadcastSticky"
+        android:description="@string/permdesc_broadcastSticky"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows mounting and unmounting file systems for removable storage.
     <p>Not for use by third-party applications.-->
     <permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows formatting file systems for removable storage.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @hide -->
     <permission android:name="android.permission.STORAGE_INTERNAL"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows access to ASEC non-destructive API calls
          @hide  -->
     <permission android:name="android.permission.ASEC_ACCESS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows creation of ASEC volumes
          @hide  -->
     <permission android:name="android.permission.ASEC_CREATE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows destruction of ASEC volumes
          @hide  -->
     <permission android:name="android.permission.ASEC_DESTROY"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows mount / unmount of ASEC volumes
          @hide  -->
     <permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows rename of ASEC volumes
          @hide  -->
     <permission android:name="android.permission.ASEC_RENAME"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows applications to write the apn settings.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WRITE_APN_SETTINGS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows applications to change network connectivity state.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.CHANGE_NETWORK_STATE"
-                android:description="@string/permdesc_changeNetworkState"
-                android:label="@string/permlab_changeNetworkState"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_changeNetworkState"
+        android:label="@string/permlab_changeNetworkState"
+        android:protectionLevel="normal" />
 
     <!-- Allows an application to clear the caches of all installed
          applications on the device.
          <p>Protection level: system|signature
     -->
     <permission android:name="android.permission.CLEAR_APP_CACHE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to use any media decoder when decoding for playback
          @hide -->
     <permission android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to install and/or uninstall CA certificates on
          behalf of the user.
          @hide -->
     <permission android:name="android.permission.MANAGE_CA_CERTIFICATES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to do certain operations needed for
          interacting with the recovery (system update) system.
          @hide -->
     <permission android:name="android.permission.RECOVERY"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows the system to bind to an application's task services
          @hide -->
     <permission android:name="android.permission.BIND_JOB_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
     <uses-permission android:name="android.permission.BIND_JOB_SERVICE"/>
 
     <!-- Allows an application to initiate configuration updates
@@ -2015,12 +2009,7 @@
          it off to the various individual installer components
          @hide -->
     <permission android:name="android.permission.UPDATE_CONFIG"
-                android:protectionLevel="signature|privileged" />
-
-    <!-- Allows the system to reset throttling in shortcut manager.
-         @hide -->
-    <permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
@@ -2030,40 +2019,40 @@
     <!-- @SystemApi Allows an application to read or write the secure system settings.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WRITE_SECURE_SETTINGS"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Allows an application to retrieve state dump information from system services.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DUMP"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Allows an application to read the low-level system log files.
     <p>Not for use by third-party applications, because
     Log entries can contain the user's private information. -->
     <permission android:name="android.permission.READ_LOGS"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Configure an application for debugging.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_DEBUG_APP"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Allows an application to set the maximum number of (not needed)
          application processes that can be running.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_PROCESS_LIMIT"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Allows an application to control whether activities are immediately
          finished when put in the background.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_ALWAYS_FINISH"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Allow an application to request that a signal be sent to all persistent processes.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- ==================================== -->
     <!-- Private permissions                  -->
@@ -2072,34 +2061,34 @@
 
     <!-- @SystemApi Allows access to the list of accounts in the Accounts Service. -->
     <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows but does not guarantee access to user passwords at the conclusion of add account
     @hide -->
     <permission android:name="android.permission.GET_PASSWORD"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows applications to RW to diagnostic resources.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DIAGNOSTIC"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to open, close, or disable the status bar
          and its icons.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.STATUS_BAR"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to be the status bar.  Currently used only by SystemUI.apk
     @hide -->
     <permission android:name="android.permission.STATUS_BAR_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to bind to third party quick settings tiles.
          <p>Should only be requested by the System, should be required by
          TileService declarations.-->
     <permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to force a BACK operation on whatever is the
          top activity.
@@ -2107,28 +2096,28 @@
          @hide
     -->
     <permission android:name="android.permission.FORCE_BACK"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to update device statistics.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.UPDATE_DEVICE_STATS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @hide Allows an application to collect battery statistics -->
     <permission android:name="android.permission.GET_APP_OPS_STATS"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Allows an application to update application operation statistics. Not for
          use by third party apps.
          @hide -->
     <permission android:name="android.permission.UPDATE_APP_OPS_STATS"
-                android:protectionLevel="signature|privileged|installer" />
+        android:protectionLevel="signature|privileged|installer" />
 
     <!-- @SystemApi Allows an application to update the user app op restrictions.
          Not for use by third party apps.
          @hide -->
     <permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS"
-                android:protectionLevel="signature|installer" />
+        android:protectionLevel="signature|installer" />
 
     <!-- @SystemApi Allows an application to open windows that are for use by parts
          of the system user interface.
@@ -2136,7 +2125,7 @@
          @hide
     -->
     <permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to manage (create, destroy,
          Z-order) application tokens in the window manager.
@@ -2144,17 +2133,17 @@
          @hide
     -->
     <permission android:name="android.permission.MANAGE_APP_TOKENS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows System UI to register listeners for events from Window Manager.
          @hide -->
     <permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Allows the application to temporarily freeze the screen for a
          full-screen transition. -->
     <permission android:name="android.permission.FREEZE_SCREEN"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to inject user events (keys, touch, trackball)
          into the event stream and deliver them to ANY window.  Without this
@@ -2163,24 +2152,24 @@
          @hide
     -->
     <permission android:name="android.permission.INJECT_EVENTS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to register an input filter which filters the stream
          of user events (keys, touch, trackball) before they are dispatched to any window. -->
     <permission android:name="android.permission.FILTER_EVENTS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to retrieve the window token from the accessibility manager. -->
     <permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to collect frame statistics -->
     <permission android:name="android.permission.FRAME_STATS"
-                android:protectionLevel="signature" />
+         android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to temporary enable accessibility on the device. -->
     <permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to watch and control how activities are
          started globally in the system.  Only for is in debugging
@@ -2189,13 +2178,13 @@
          @hide
     -->
     <permission android:name="android.permission.SET_ACTIVITY_WATCHER"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to call the activity manager shutdown() API
          to put the higher-level system there into a shutdown state.
          @hide -->
     <permission android:name="android.permission.SHUTDOWN"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to tell the activity manager to temporarily
          stop application switches, putting it into a special mode that
@@ -2203,7 +2192,7 @@
          critical UI such as the home screen.
          @hide -->
     <permission android:name="android.permission.STOP_APP_SWITCHES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to retrieve private information about
          the current top activity, such as any assist context it can provide.
@@ -2211,42 +2200,42 @@
          @hide
     -->
     <permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to retrieve the current state of keys and
          switches.
          <p>Not for use by third-party applications.
          @deprecated The API that used this permission has been removed. -->
     <permission android:name="android.permission.READ_INPUT_STATE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.inputmethodservice.InputMethodService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_INPUT_METHOD"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.media.midi.MidiDeviceService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_MIDI_DEVICE_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.printservice.PrintService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_PRINT_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.printservice.recommendation.RecommendationService},
      to ensure that only the system can bind to it.
@@ -2255,7 +2244,7 @@
      <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
-                android:protectionLevel="signature" />
+            android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
          or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
@@ -2263,65 +2252,65 @@
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_NFC_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by the PrintSpooler to ensure that only the system can bind to it.
          @hide -->
     <permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Must be required by the RuntimePermissionPresenterService to ensure
          that only the system can bind to it.
          @hide -->
     <permission android:name="android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by a TextService (e.g. SpellCheckerService)
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_TEXT_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.net.VpnService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_VPN_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
          to ensure that only the system can bind to it.
          <p>Protection level: system|signature
     -->
     <permission android:name="android.permission.BIND_WALLPAPER"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_VOICE_INTERACTION"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by hotword enrollment application,
          to ensure that only the system can interact with it.
          @hide <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
          to ensure that only the system can bind to it.
          @hide -->
     <permission android:name="android.permission.BIND_REMOTE_DISPLAY"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.media.tv.TvInputService}
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_TV_INPUT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi
          Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider}
@@ -2330,7 +2319,7 @@
          <p>Not for use by third-party applications. </p>
          @hide  -->
     <permission android:name="android.permission.BIND_TV_REMOTE_SERVICE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi
          Must be required for a virtual remote controller for TV.
@@ -2338,32 +2327,32 @@
          <p>Not for use by third-party applications. </p>
          @hide  -->
     <permission android:name="android.permission.TV_VIRTUAL_REMOTE_CONTROLLER"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to modify parental controls
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.media.routing.MediaRouteService}
          to ensure that only the system can interact with it.
          @hide -->
     <permission android:name="android.permission.BIND_ROUTE_PROVIDER"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by device administration receiver, to ensure that only the
          system can interact with it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_DEVICE_ADMIN"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Required to add or remove another application as a device admin.
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows low-level access to setting the orientation (actually
          rotation) of the screen.
@@ -2371,33 +2360,33 @@
          @hide
     -->
     <permission android:name="android.permission.SET_ORIENTATION"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows low-level access to setting the pointer speed.
          <p>Not for use by third-party applications.
          @hide
     -->
     <permission android:name="android.permission.SET_POINTER_SPEED"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows low-level access to setting input device calibration.
          <p>Not for use by normal applications.
          @hide -->
     <permission android:name="android.permission.SET_INPUT_CALIBRATION"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows low-level access to setting the keyboard layout.
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to query tablet mode state and monitor changes
          in it.
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.TABLET_MODE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to request installing packages. Apps
          targeting APIs greater than 22 must hold this permission in
@@ -2405,41 +2394,41 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
-                android:label="@string/permlab_requestInstallPackages"
-                android:description="@string/permdesc_requestInstallPackages"
-                android:protectionLevel="normal" />
+        android:label="@string/permlab_requestInstallPackages"
+        android:description="@string/permdesc_requestInstallPackages"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows an application to install packages.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.INSTALL_PACKAGES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to clear user data.
          <p>Not for use by third-party applications
          @hide
     -->
     <permission android:name="android.permission.CLEAR_APP_USER_DATA"
-                android:protectionLevel="signature|installer" />
+        android:protectionLevel="signature|installer" />
 
     <!-- @hide Allows an application to get the URI permissions
          granted to another application.
          <p>Not for use by third-party applications
     -->
     <permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to clear the URI permissions
          granted to another application.
          <p>Not for use by third-party applications
     -->
     <permission
-            android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS"
-            android:protectionLevel="signature" />
+        android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS"
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to delete cache files.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DELETE_CACHE_FILES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to delete packages.
          <p>Not for use by third-party applications.
@@ -2447,251 +2436,251 @@
          when the application deleting the package is not the same application that installed the
          package. -->
     <permission android:name="android.permission.DELETE_PACKAGES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to move location of installed package.
          @hide -->
     <permission android:name="android.permission.MOVE_PACKAGE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to change whether an application component (other than its own) is
          enabled or not.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to grant specific permissions.
          @hide -->
     <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS"
-                android:protectionLevel="signature|installer|verifier" />
+        android:protectionLevel="signature|installer|verifier" />
 
     <!-- @SystemApi Allows an app that has this permission and the permissions to install packages
          to request certain runtime permissions to be granted at installation.
          @hide -->
     <permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
-                android:protectionLevel="signature|installer|verifier" />
+        android:protectionLevel="signature|installer|verifier" />
 
     <!-- @SystemApi Allows an application to revoke specific permissions.
         @hide -->
     <permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
-                android:protectionLevel="signature|installer|verifier" />
+         android:protectionLevel="signature|installer|verifier" />
 
     <!-- @hide Allows an application to observe permission changes. -->
     <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
          <p>Not for use by third-party applications.
          @hide
     -->
     <permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to take screen shots and more generally
          get access to the frame buffer data.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_FRAME_BUFFER"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to use InputFlinger's low level features.
          @hide -->
     <permission android:name="android.permission.ACCESS_INPUT_FLINGER"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to configure and connect to Wifi displays
          @hide -->
     <permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to control low-level features of Wifi displays
          such as opening an RTSP socket.  This permission should only be used
          by the display manager.
          @hide -->
     <permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to control the color transforms applied to
          displays system-wide.
          <p>Not for use by third-party applications.</p>
          @hide -->
     <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to control VPN.
          <p>Not for use by third-party applications.</p>
          @hide -->
     <permission android:name="android.permission.CONTROL_VPN"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
 
     <!-- @SystemApi Allows an application to capture audio output.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to capture audio for hotword detection.
          <p>Not for use by third-party applications.</p>
          @hide -->
     <permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to modify audio routing and override policy decisions.
          <p>Not for use by third-party applications.</p>
          @hide -->
     <permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to capture video output.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to capture secure video output.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to know what content is playing and control its playback.
          <p>Not for use by third-party applications due to privacy of media consumption</p>  -->
     <permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Required to be able to disable the device (very dangerous!).
          <p>Not for use by third-party applications.
          @hide
     -->
     <permission android:name="android.permission.BRICK"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Required to be able to reboot the device.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.REBOOT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows low-level access to power management.
-         <p>Not for use by third-party applications.
-         @hide
-     -->
-    <permission android:name="android.permission.DEVICE_POWER"
-                android:protectionLevel="signature" />
+   <!-- @SystemApi Allows low-level access to power management.
+        <p>Not for use by third-party applications.
+        @hide
+    -->
+   <permission android:name="android.permission.DEVICE_POWER"
+        android:protectionLevel="signature" />
 
-    <!-- Allows access to the PowerManager.userActivity function.
-    <p>Not for use by third-party applications. @hide @SystemApi -->
+   <!-- Allows access to the PowerManager.userActivity function.
+   <p>Not for use by third-party applications. @hide @SystemApi -->
     <permission android:name="android.permission.USER_ACTIVITY"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
-    <!-- @hide Allows low-level access to tun tap driver -->
+   <!-- @hide Allows low-level access to tun tap driver -->
     <permission android:name="android.permission.NET_TUNNELING"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Run as a manufacturer test application, running as the root user.
          Only available when the device is running in manufacturer test mode.
          <p>Not for use by third-party applications.
     -->
     <permission android:name="android.permission.FACTORY_TEST"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast a notification that an application
          package has been removed.
          <p>Not for use by third-party applications.
     -->
     <permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast an SMS receipt notification.
          <p>Not for use by third-party applications.
     -->
     <permission android:name="android.permission.BROADCAST_SMS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast a WAP PUSH receipt notification.
          <p>Not for use by third-party applications.
     -->
     <permission android:name="android.permission.BROADCAST_WAP_PUSH"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to broadcast privileged networking requests.
          <p>Not for use by third-party applications. @hide -->
     <permission android:name="android.permission.BROADCAST_NETWORK_PRIVILEGED"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Not for use by third-party applications. -->
     <permission android:name="android.permission.MASTER_CLEAR"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to call any phone number, including emergency
          numbers, without going through the Dialer user interface for the user
          to confirm the call being placed.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CALL_PRIVILEGED"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to perform CDMA OTA provisioning @hide -->
     <permission android:name="android.permission.PERFORM_CDMA_PROVISIONING"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to perform SIM Activation @hide -->
     <permission android:name="android.permission.PERFORM_SIM_ACTIVATION"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows enabling/disabling location update notifications from
          the radio.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CONTROL_LOCATION_UPDATES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows read/write access to the "properties" table in the checkin
          database, to change values that get uploaded.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to collect component usage
          statistics
          <p>Declaring the permission implies intention to use the API and the user of the
          device can grant permission through the Settings application. -->
     <permission android:name="android.permission.PACKAGE_USAGE_STATS"
-                android:protectionLevel="signature|privileged|development|appop" />
+        android:protectionLevel="signature|privileged|development|appop" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
     <!-- @hide Allows an application to change the app idle state of an app.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide @SystemApi Allows an application to temporarily whitelist an inactive app to
          access the network and acquire wakelocks.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Permission an application must hold in order to use
          {@link android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}.
          This is a normal permission: an app requesting it will always be granted the
          permission, without the user needing to approve or see it. -->
     <permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
-                android:protectionLevel="normal" />
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows an application to collect battery statistics -->
     <permission android:name="android.permission.BATTERY_STATS"
-                android:protectionLevel="signature|privileged|development" />
+        android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Allows an application to control the backup and restore process.
     <p>Not for use by third-party applications.
          @hide pending API council -->
     <permission android:name="android.permission.BACKUP"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows a package to launch the secure full-backup confirmation UI.
          ONLY the system process may hold this permission.
          @hide -->
     <permission android:name="android.permission.CONFIRM_FULL_BACKUP"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Must be required by a {@link android.widget.RemoteViewsService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_REMOTEVIEWS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to tell the AppWidget service which application
          can access AppWidget's data.  The normal user flow is that a user
@@ -2700,25 +2689,25 @@
          An application that has this permission should honor that contract.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BIND_APPWIDGET"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Private permission, to restrict who can bring up a dialog to add a new
          keyguard widget
          @hide -->
     <permission android:name="android.permission.BIND_KEYGUARD_APPWIDGET"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Internal permission allowing an application to query/set which
          applications can bind AppWidgets.
          @hide -->
     <permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows applications to change the background data setting.
     <p>Not for use by third-party applications.
          @hide pending API council -->
     <permission android:name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi This permission can be used on content providers to allow the global
          search system to access their data.  Typically it used when the
@@ -2729,7 +2718,7 @@
          it is used by applications to protect themselves from everyone else
          besides global search. -->
     <permission android:name="android.permission.GLOBAL_SEARCH"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Internal permission protecting access to the global search
          system: ensures that only the system can access the provider
@@ -2739,33 +2728,33 @@
          ranking).
          @hide -->
     <permission android:name="android.permission.GLOBAL_SEARCH_CONTROL"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Internal permission to allows an application to read indexable data.
         @hide -->
     <permission android:name="android.permission.READ_SEARCH_INDEXABLES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows applications to set a live wallpaper.
          @hide XXX Change to signature once the picker is moved to its
          own apk as Ghod Intended. -->
     <permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows applications to read dream settings and dream state.
          @hide -->
     <permission android:name="android.permission.READ_DREAM_STATE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows applications to write dream settings, and start or stop dreaming.
          @hide -->
     <permission android:name="android.permission.WRITE_DREAM_STATE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allow an application to read and write the cache partition.
          @hide -->
     <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by default container service so that only
          the system can bind to it and use it to copy
@@ -2773,67 +2762,67 @@
          accessible to the system.
          @hide -->
     <permission android:name="android.permission.COPY_PROTECTED_DATA"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Internal permission protecting access to the encryption methods
         @hide
     -->
     <permission android:name="android.permission.CRYPT_KEEPER"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to read historical network usage for
          specific networks and applications. @hide -->
     <permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to manage network policies (such as warning and disable
          limits) and to define application-specific rules. @hide -->
     <permission android:name="android.permission.MANAGE_NETWORK_POLICY"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to account its network traffic against other UIDs. Used
          by system services like download manager and media server. Not for use by
          third party apps. @hide -->
     <permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- C2DM permission.
          @hide Used internally.
      -->
     <permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"
-                android:protectionLevel="signature" />
+          android:protectionLevel="signature" />
     <uses-permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"/>
 
     <!-- @SystemApi @hide Package verifier needs to have this permission before the PackageManager will
          trust it to verify packages.
     -->
     <permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by package verifier receiver, to ensure that only the
          system can interact with it.
          @hide
     -->
     <permission android:name="android.permission.BIND_PACKAGE_VERIFIER"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi @hide Intent filter verifier needs to have this permission before the
          PackageManager will trust it to verify intent filters.
     -->
     <permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by intent filter verifier receiver, to ensure that only the
          system can interact with it.
          @hide
     -->
     <permission android:name="android.permission.BIND_INTENT_FILTER_VERIFIER"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows applications to access serial ports via the SerialManager.
          @hide -->
     <permission android:name="android.permission.SERIAL_PORT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows the holder to access content providers from outside an ApplicationThread.
          This permission is enforced by the ActivityManagerService on the corresponding APIs,
@@ -2842,27 +2831,27 @@
          @hide
     -->
     <permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to hold an UpdateLock, recommending that a headless
          OTA reboot *not* occur while the lock is held.
          @hide -->
     <permission android:name="android.permission.UPDATE_LOCK"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to read the current set of notifications, including
          any metadata and intents attached.
          @hide -->
     <permission android:name="android.permission.ACCESS_NOTIFICATIONS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Marker permission for applications that wish to access notification policy.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"
-                android:description="@string/permdesc_access_notification_policy"
-                android:label="@string/permlab_access_notification_policy"
-                android:protectionLevel="normal" />
+        android:description="@string/permdesc_access_notification_policy"
+        android:label="@string/permlab_access_notification_policy"
+        android:protectionLevel="normal" />
 
     <!-- Allows modification of do not disturb rules and policies. Only allowed for system
         processes.
@@ -2873,42 +2862,42 @@
     <!-- Allows access to keyguard secure storage.  Only allowed for system processes.
         @hide -->
     <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
     <permission android:name="android.permission.MANAGE_FINGERPRINT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
     <permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to control keyguard.  Only allowed for system processes.
         @hide -->
     <permission android:name="android.permission.CONTROL_KEYGUARD"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to listen to trust changes.  Only allowed for system processes.
         @hide -->
     <permission android:name="android.permission.TRUST_LISTENER"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to provide a trust agent.
          @hide For security reasons, this is a platform-only permission. -->
     <permission android:name="android.permission.PROVIDE_TRUST_AGENT"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to launch the trust agent settings activity.
         @hide -->
     <permission android:name="android.permission.LAUNCH_TRUST_AGENT_SETTINGS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Must be required by an {@link
         android.service.trust.TrustAgentService},
         to ensure that only the system can bind to it.
         @hide -->
     <permission android:name="android.permission.BIND_TRUST_AGENT"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link
          android.service.notification.NotificationListenerService},
@@ -2916,7 +2905,7 @@
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link
          android.service.notification.NotificationRankerService         to ensure that only the system can bind to it.
@@ -2924,7 +2913,7 @@
          @hide This is not a third-party API (intended for system apps). -->
     -->
     <permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link
          android.service.chooser.ChooserTargetService}, to ensure that
@@ -2932,7 +2921,7 @@
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link
          android.service.notification.ConditionProviderService},
@@ -2940,57 +2929,57 @@
          <p>Protection level: signature
          -->
     <permission android:name="android.permission.BIND_CONDITION_PROVIDER_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.service.dreams.DreamService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_DREAM_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to call into a carrier setup flow. It is up to the
          carrier setup application to enforce that this permission is required
          @hide This is not a third-party API (intended for OEMs and system apps). -->
     <permission android:name="android.permission.INVOKE_CARRIER_SETUP"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to listen for network condition observations.
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.ACCESS_NETWORK_CONDITIONS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to provision and access DRM certificates
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Api Allows an application to manage media projection sessions.
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to read install sessions
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.READ_INSTALL_SESSIONS"
-                android:label="@string/permlab_readInstallSessions"
-                android:description="@string/permdesc_readInstallSessions"
-                android:protectionLevel="normal"/>
+        android:label="@string/permlab_readInstallSessions"
+        android:description="@string/permdesc_readInstallSessions"
+        android:protectionLevel="normal"/>
 
     <!-- @SystemApi Allows an application to remove DRM certificates
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.REMOVE_DRM_CERTIFICATES"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @deprecated Use {@link android.Manifest.permission#BIND_CARRIER_SERVICES} instead -->
     <permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to interact with the currently active
          {@link android.service.voice.VoiceInteractionService}.
          @hide -->
     <permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- The system process that is allowed to bind to services in carrier apps will
          have this permission. Carrier apps should use this permission to protect
@@ -2998,9 +2987,9 @@
          <p>Protection level: system|signature
     -->
     <permission android:name="android.permission.BIND_CARRIER_SERVICES"
-                android:label="@string/permlab_bindCarrierServices"
-                android:description="@string/permdesc_bindCarrierServices"
-                android:protectionLevel="signature|privileged" />
+        android:label="@string/permlab_bindCarrierServices"
+        android:description="@string/permdesc_bindCarrierServices"
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to query whether DO_NOT_ASK_CREDENTIALS_ON_BOOT
          flag is set.
@@ -3046,7 +3035,7 @@
     <!-- Allows the holder to access the ephemeral applications on the device.
     @hide -->
     <permission android:name="android.permission.ACCESS_EPHEMERAL_APPS"
-                android:protectionLevel="signature" />
+            android:protectionLevel="signature" />
 
     <!-- Allows receiving the usage of media resource e.g. video/audio codec and
          graphic memory.
@@ -3058,7 +3047,7 @@
          APIs given by {@link SoundTriggerManager}.
          @hide <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.MANAGE_SOUND_TRIGGER"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows trusted applications to dispatch managed provisioning message to Managed
          Provisioning app. If requesting app does not have permission, it will be ignored.
@@ -3082,17 +3071,17 @@
          the system can bind to it.
          <p>Protection level: signature -->
     <permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- Required to make calls to {@link android.service.vr.IVrManager}.
          @hide -->
     <permission android:name="android.permission.ACCESS_VR_MANAGER"
-                android:protectionLevel="signature" />
+            android:protectionLevel="signature" />
 
     <!-- Allows an application to whitelist tasks during lock task mode
          @hide <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
-                android:protectionLevel="signature|setup" />
+        android:protectionLevel="signature|setup" />
 
     <!-- @SystemApi Allows an application to replace the app name displayed alongside notifications
          in the N-release and later.
@@ -3113,13 +3102,12 @@
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
         <activity android:name="com.android.internal.app.ChooserActivity"
-                  android:theme="@style/Theme.DeviceDefault.Resolver"
-                  android:finishOnCloseSystemDialogs="true"
-                  android:excludeFromRecents="true"
-                  android:documentLaunchMode="never"
-                  android:relinquishTaskIdentity="true"
-                  android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
-                  android:process=":ui">
+                android:theme="@style/Theme.DeviceDefault.Resolver"
+                android:finishOnCloseSystemDialogs="true"
+                android:excludeFromRecents="true"
+                android:documentLaunchMode="never"
+                android:relinquishTaskIdentity="true"
+                android:process=":ui">
             <intent-filter>
                 <action android:name="android.intent.action.CHOOSER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3127,102 +3115,102 @@
             </intent-filter>
         </activity>
         <activity android:name="com.android.internal.app.IntentForwarderActivity"
-                  android:finishOnCloseSystemDialogs="true"
-                  android:theme="@style/Theme.NoDisplay"
-                  android:excludeFromRecents="true"
-                  android:label="@string/user_owner_label"
-                  android:exported="true"
-        >
+                android:finishOnCloseSystemDialogs="true"
+                android:theme="@style/Theme.NoDisplay"
+                android:excludeFromRecents="true"
+                android:label="@string/user_owner_label"
+                android:exported="true"
+                >
         </activity>
         <activity-alias android:name="com.android.internal.app.ForwardIntentToParent"
-                        android:targetActivity="com.android.internal.app.IntentForwarderActivity"
-                        android:exported="true"
-                        android:label="@string/user_owner_label">
+                android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+                android:exported="true"
+                android:label="@string/user_owner_label">
         </activity-alias>
         <activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
-                        android:targetActivity="com.android.internal.app.IntentForwarderActivity"
-                        android:icon="@drawable/ic_corp_icon"
-                        android:exported="true"
-                        android:label="@string/managed_profile_label">
+                android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+                android:icon="@drawable/ic_corp_icon"
+                android:exported="true"
+                android:label="@string/managed_profile_label">
         </activity-alias>
         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
-                  android:theme="@style/Theme.Material.Light.Dialog"
-                  android:label="@string/heavy_weight_switcher_title"
-                  android:finishOnCloseSystemDialogs="true"
-                  android:excludeFromRecents="true"
-                  android:process=":ui">
+                android:theme="@style/Theme.Material.Light.Dialog"
+                android:label="@string/heavy_weight_switcher_title"
+                android:finishOnCloseSystemDialogs="true"
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
         <activity android:name="com.android.internal.app.PlatLogoActivity"
-                  android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
-                  android:configChanges="orientation|keyboardHidden"
-                  android:process=":ui">
+                android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+                android:configChanges="orientation|keyboardHidden"
+                android:process=":ui">
         </activity>
         <activity android:name="com.android.internal.app.DisableCarModeActivity"
-                  android:theme="@style/Theme.NoDisplay"
-                  android:excludeFromRecents="true"
-                  android:process=":ui">
+                android:theme="@style/Theme.NoDisplay"
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
         <activity android:name="com.android.internal.app.DumpHeapActivity"
-                  android:theme="@style/Theme.Translucent.NoTitleBar"
-                  android:label="@string/dump_heap_title"
-                  android:finishOnCloseSystemDialogs="true"
-                  android:noHistory="true"
-                  android:excludeFromRecents="true"
-                  android:process=":ui">
+                android:theme="@style/Theme.Translucent.NoTitleBar"
+                android:label="@string/dump_heap_title"
+                android:finishOnCloseSystemDialogs="true"
+                android:noHistory="true"
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
         <provider android:name="com.android.server.am.DumpHeapProvider"
-                  android:authorities="com.android.server.heapdump"
-                  android:grantUriPermissions="true"
-                  android:multiprocess="false"
-                  android:singleUser="true" />
+                android:authorities="com.android.server.heapdump"
+                android:grantUriPermissions="true"
+                android:multiprocess="false"
+                android:singleUser="true" />
 
         <activity android:name="android.accounts.ChooseAccountActivity"
-                  android:excludeFromRecents="true"
-                  android:exported="true"
-                  android:theme="@style/Theme.Material.Light.Dialog"
-                  android:label="@string/choose_account_label"
-                  android:process=":ui">
+                android:excludeFromRecents="true"
+                android:exported="true"
+                android:theme="@style/Theme.Material.Light.Dialog"
+                android:label="@string/choose_account_label"
+                android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
-                  android:excludeFromRecents="true"
-                  android:exported="true"
-                  android:theme="@style/Theme.Material.Light.Dialog"
-                  android:label="@string/choose_account_label"
-                  android:process=":ui">
+                android:excludeFromRecents="true"
+                android:exported="true"
+                android:theme="@style/Theme.Material.Light.Dialog"
+                android:label="@string/choose_account_label"
+                android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.ChooseAccountTypeActivity"
-                  android:excludeFromRecents="true"
-                  android:theme="@style/Theme.Material.Light.Dialog"
-                  android:label="@string/choose_account_label"
-                  android:process=":ui">
+                android:excludeFromRecents="true"
+                android:theme="@style/Theme.Material.Light.Dialog"
+                android:label="@string/choose_account_label"
+                android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.CantAddAccountActivity"
-                  android:excludeFromRecents="true"
-                  android:exported="true"
-                  android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
-                  android:process=":ui">
+                android:excludeFromRecents="true"
+                android:exported="true"
+                android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
+                android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
-                  android:excludeFromRecents="true"
-                  android:exported="true"
-                  android:theme="@style/Theme.Material.Light.DialogWhenLarge"
-                  android:process=":ui">
+                android:excludeFromRecents="true"
+                android:exported="true"
+                android:theme="@style/Theme.Material.Light.DialogWhenLarge"
+                android:process=":ui">
         </activity>
 
         <activity android:name="android.content.SyncActivityTooManyDeletes"
-                  android:theme="@style/Theme.Material.Light.Dialog"
-                  android:label="@string/sync_too_many_deletes"
-                  android:process=":ui">
+               android:theme="@style/Theme.Material.Light.Dialog"
+               android:label="@string/sync_too_many_deletes"
+               android:process=":ui">
         </activity>
 
         <activity android:name="com.android.internal.app.ShutdownActivity"
-                  android:permission="android.permission.SHUTDOWN"
-                  android:theme="@style/Theme.NoDisplay"
-                  android:excludeFromRecents="true">
+            android:permission="android.permission.SHUTDOWN"
+            android:theme="@style/Theme.NoDisplay"
+            android:excludeFromRecents="true">
             <intent-filter>
                 <action android:name="android.intent.action.ACTION_REQUEST_SHUTDOWN" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3234,9 +3222,9 @@
         </activity>
 
         <activity android:name="com.android.internal.app.NetInitiatedActivity"
-                  android:theme="@style/Theme.Material.Light.Dialog.Alert"
-                  android:excludeFromRecents="true"
-                  android:process=":ui">
+                android:theme="@style/Theme.Material.Light.Dialog.Alert"
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
 
         <activity android:name="com.android.internal.app.SystemUserHomeActivity"
@@ -3253,9 +3241,9 @@
         <!-- Activity to prompt user if it's ok to create a new user sandbox for a
              specified account. -->
         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
-                  android:excludeFromRecents="true"
-                  android:process=":ui"
-                  android:theme="@style/Theme.Material.Light.Dialog.Alert">
+                android:excludeFromRecents="true"
+                android:process=":ui"
+                android:theme="@style/Theme.Material.Light.Dialog.Alert">
             <intent-filter android:priority="1000">
                 <action android:name="android.os.action.CREATE_USER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3263,20 +3251,20 @@
         </activity>
 
         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
-                  android:theme="@style/Theme.Material.Light.Dialog.Alert"
-                  android:excludeFromRecents="true"
-                  android:process=":ui">
+                android:theme="@style/Theme.Material.Light.Dialog.Alert"
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
 
         <receiver android:name="com.android.server.BootReceiver"
-                  android:systemUserOnly="true">
+                android:systemUserOnly="true">
             <intent-filter android:priority="1000">
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
             </intent-filter>
         </receiver>
 
         <receiver android:name="com.android.server.updates.CertPinInstallReceiver"
-                  android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_PINS" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3284,7 +3272,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver"
-                  android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_INTENT_FIREWALL" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3292,7 +3280,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.SmsShortCodesInstallReceiver"
-                  android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_SMS_SHORT_CODES" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3300,7 +3288,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.ApnDbInstallReceiver"
-                  android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_APN_DB" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3308,7 +3296,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.CarrierProvisioningUrlsInstallReceiver"
-                  android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3316,23 +3304,15 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.TzDataInstallReceiver"
-                  android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_TZDATA" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
             </intent-filter>
         </receiver>
 
-        <receiver android:name="com.android.server.updates.SELinuxPolicyInstallReceiver"
-                  android:permission="android.permission.UPDATE_CONFIG">
-            <intent-filter>
-                <action android:name="android.intent.action.UPDATE_SEPOLICY" />
-                <data android:scheme="content" android:host="*" android:mimeType="*/*" />
-            </intent-filter>
-        </receiver>
-
         <receiver android:name="com.android.server.MasterClearReceiver"
-                  android:permission="android.permission.MASTER_CLEAR">
+            android:permission="android.permission.MASTER_CLEAR">
             <intent-filter
                     android:priority="100" >
                 <!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->
@@ -3345,12 +3325,12 @@
         </receiver>
 
         <service android:name="android.hardware.location.GeofenceHardwareService"
-                 android:permission="android.permission.LOCATION_HARDWARE"
-                 android:exported="false" />
+            android:permission="android.permission.LOCATION_HARDWARE"
+            android:exported="false" />
 
         <service android:name="com.android.internal.backup.LocalTransportService"
-                 android:permission="android.permission.CONFIRM_FULL_BACKUP"
-                 android:exported="false">
+                android:permission="android.permission.CONFIRM_FULL_BACKUP"
+                android:exported="false">
             <intent-filter>
                 <action android:name="android.backup.TRANSPORT_HOST" />
             </intent-filter>
@@ -3375,9 +3355,9 @@
         </service>
 
         <service
-                android:name="com.android.server.pm.BackgroundDexOptService"
-                android:exported="true"
-                android:permission="android.permission.BIND_JOB_SERVICE">
+            android:name="com.android.server.pm.BackgroundDexOptService"
+            android:exported="true"
+            android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
     </application>
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index e8de02d..7406645 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -106,7 +106,7 @@
 
         // OEMs cannot define permissions in the platform namespace
         for (String permission : declaredPermissionsMap.keySet()) {
-            assertFalse("Cannot define permission " + permission + " in android namespace",
+            assertFalse("Cannot define permission in android namespace",
                     permission.startsWith(PLATFORM_ROOT_NAMESPACE));
         }
 
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceTest.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceTest.java
index b2907f3..6b36fee 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferenceTest.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceTest.java
@@ -24,6 +24,11 @@
 
 import android.preference2.cts.R;
 
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 public class PreferenceTest
         extends ActivityInstrumentationTestCase2<PreferenceFromCodeActivity> {
 
@@ -232,6 +237,24 @@
         }
     }
 
+    public void testPersistStringSet() {
+        CustomPreference mCustomPreference = new CustomPreference(mActivity);
+        String key = "" + Math.random();
+        mCustomPreference.setKey(key);
+        PreferenceGroup mPreferenceGroup = (PreferenceGroup) mActivity.findPreference(
+                "pref-group");
+        mPreferenceGroup.addPreference(mCustomPreference);
+        try {
+            Set<String> expected = Stream.of("a", "b", "c").collect(Collectors.toSet());
+            boolean result = mCustomPreference.persistStringSet(expected);
+            assertTrue(result);
+            Set<String> actual = mCustomPreference.getPersistedStringSet(new HashSet<>());
+            assertEquals(expected, actual);
+        } finally {
+            mPreferenceGroup.removePreference(mCustomPreference);
+        }
+    }
+
     public void testPersistFloat() {
         CustomPreference mCustomPreference = new CustomPreference(mActivity);
         String key = "" + Math.random();
diff --git a/tests/tests/print/Android.mk b/tests/tests/print/Android.mk
index bceaacc..d0c1a81 100644
--- a/tests/tests/print/Android.mk
+++ b/tests/tests/print/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_PACKAGE_NAME := CtsPrintTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner ub-uiautomator ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner ub-uiautomator ctsdeviceutil android-support-test
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/tests/tests/print/AndroidManifest.xml b/tests/tests/print/AndroidManifest.xml
index bd58d3b..564bcb1 100644
--- a/tests/tests/print/AndroidManifest.xml
+++ b/tests/tests/print/AndroidManifest.xml
@@ -64,7 +64,8 @@
         <activity
             android:name="android.print.cts.services.CustomPrintOptionsActivity"
             android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
-            android:exported="true">
+            android:exported="true"
+            android:theme="@style/Theme.Translucent">
         </activity>
 
   </application>
diff --git a/tests/tests/print/res/raw/yellow.png b/tests/tests/print/res/raw/yellow.png
new file mode 100644
index 0000000..3e2bbd3
--- /dev/null
+++ b/tests/tests/print/res/raw/yellow.png
Binary files differ
diff --git a/tests/tests/print/res/raw/yellow_printer.png b/tests/tests/print/res/raw/yellow_printer.png
deleted file mode 100644
index 2e1cc8d..0000000
--- a/tests/tests/print/res/raw/yellow_printer.png
+++ /dev/null
Binary files differ
diff --git a/tests/tests/print/res/values/themes.xml b/tests/tests/print/res/values/themes.xml
new file mode 100644
index 0000000..f5c9b977
--- /dev/null
+++ b/tests/tests/print/res/values/themes.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<resources>
+    <style name="Theme.Translucent" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:windowIsTranslucent">true</item>
+    </style>
+</resources>
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index 7f0ae5d..af67e13 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -16,6 +16,7 @@
 
 package android.print.cts;
 
+import static android.print.cts.Utils.getPrintManager;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
@@ -24,15 +25,12 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import android.content.Context;
 import android.content.pm.PackageManager;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.cts.util.SystemUtil;
 import android.graphics.pdf.PdfDocument;
 import android.os.Bundle;
 import android.os.CancellationSignal;
-import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
 import android.print.PageRange;
@@ -40,22 +38,23 @@
 import android.print.PrintDocumentAdapter;
 import android.print.PrintDocumentAdapter.LayoutResultCallback;
 import android.print.PrintDocumentAdapter.WriteResultCallback;
-import android.print.PrintManager;
+import android.print.PrintDocumentInfo;
 import android.print.PrinterId;
 import android.print.cts.services.PrintServiceCallbacks;
 import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.StubbablePrintService;
 import android.print.cts.services.StubbablePrinterDiscoverySession;
 import android.print.pdf.PrintedPdfDocument;
 import android.printservice.CustomPrinterIconCallback;
 import android.printservice.PrintJob;
-import android.printservice.PrintService;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.support.test.uiautomator.UiSelector;
 import android.test.InstrumentationTestCase;
-import android.util.DisplayMetrics;
 import android.util.Log;
 
 import org.hamcrest.BaseMatcher;
@@ -71,7 +70,6 @@
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
 import java.util.concurrent.TimeoutException;
 /**
  * This is the base class for print tests.
@@ -79,14 +77,16 @@
 public abstract class BasePrintTest extends InstrumentationTestCase {
     private final static String LOG_TAG = "BasePrintTest";
 
-    protected static final long OPERATION_TIMEOUT_MILLIS = 60000;
+    static final long OPERATION_TIMEOUT_MILLIS = 60000;
+    static final String PRINT_JOB_NAME = "Test";
+
     private static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
-    protected static final String PRINT_JOB_NAME = "Test";
     private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
     private static final String COMMAND_LIST_ENABLED_IME_COMPONENTS = "ime list -s";
     private static final String COMMAND_PREFIX_ENABLE_IME = "ime enable ";
     private static final String COMMAND_PREFIX_DISABLE_IME = "ime disable ";
     private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT
+    private static final String PRINTSPOOLER_PACKAGE = "com.android.printspooler";
 
     private static PrintDocumentActivity sActivity;
     private UiDevice mUiDevice;
@@ -100,8 +100,6 @@
         return mUiDevice;
     }
 
-    private LocaleList mOldLocale;
-
     private CallCounter mCancelOperationCounter;
     private CallCounter mLayoutCallCounter;
     private CallCounter mWriteCallCounter;
@@ -180,18 +178,6 @@
         System.setProperty("dexmaker.dexcache", getInstrumentation()
                 .getTargetContext().getCacheDir().getPath());
 
-        // Set to US locale.
-        Log.d(LOG_TAG, "set locale");
-        Resources resources = getInstrumentation().getTargetContext().getResources();
-        Configuration oldConfiguration = resources.getConfiguration();
-        if (!oldConfiguration.getLocales().get(0).equals(Locale.US)) {
-            mOldLocale = oldConfiguration.getLocales();
-            DisplayMetrics displayMetrics = resources.getDisplayMetrics();
-            Configuration newConfiguration = new Configuration(oldConfiguration);
-            newConfiguration.setLocale(Locale.US);
-            resources.updateConfiguration(newConfiguration, displayMetrics);
-        }
-
         // Initialize the latches.
         Log.d(LOG_TAG, "init counters");
         mCancelOperationCounter = new CallCounter();
@@ -226,17 +212,6 @@
         Log.d(LOG_TAG, "enableImes()");
         enableImes();
 
-        // Restore the locale if needed.
-        Log.d(LOG_TAG, "restore locale");
-        if (mOldLocale != null) {
-            Resources resources = getInstrumentation().getTargetContext().getResources();
-            DisplayMetrics displayMetrics = resources.getDisplayMetrics();
-            Configuration newConfiguration = new Configuration(resources.getConfiguration());
-            newConfiguration.setLocales(mOldLocale);
-            mOldLocale = null;
-            resources.updateConfiguration(newConfiguration, displayMetrics);
-        }
-
         // Make sure the spooler is cleaned, this also un-approves all services
         Log.d(LOG_TAG, "clearPrintSpoolerData()");
         clearPrintSpoolerData();
@@ -246,30 +221,40 @@
     }
 
     protected void print(final PrintDocumentAdapter adapter, final PrintAttributes attributes) {
-        // Initiate printing as if coming from the app.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                PrintManager printManager = (PrintManager) getActivity()
-                        .getSystemService(Context.PRINT_SERVICE);
-                printManager.print("Print job", adapter, attributes);
-            }
-        });
+        print(adapter, "Print job", attributes);
     }
 
     protected void print(PrintDocumentAdapter adapter) {
-        print(adapter, null);
+        print(adapter, (PrintAttributes) null);
     }
 
-    protected void onCancelOperationCalled() {
+    protected void print(PrintDocumentAdapter adapter, String printJobName) {
+        print(adapter, printJobName, null);
+    }
+
+    /**
+     * Start printing
+     *
+     * @param adapter      Adapter supplying data to print
+     * @param printJobName The name of the print job
+     */
+    protected void print(@NonNull PrintDocumentAdapter adapter, @NonNull String printJobName,
+            @Nullable PrintAttributes attributes) {
+        // Initiate printing as if coming from the app.
+        getInstrumentation()
+                .runOnMainSync(() -> getPrintManager(getActivity()).print(printJobName, adapter,
+                        attributes));
+    }
+
+    void onCancelOperationCalled() {
         mCancelOperationCounter.call();
     }
 
-    protected void onLayoutCalled() {
+    void onLayoutCalled() {
         mLayoutCallCounter.call();
     }
 
-    protected int getWriteCallCount() {
+    int getWriteCallCount() {
         return mWriteCallCounter.getCallCount();
     }
 
@@ -277,15 +262,15 @@
         mWriteCallCounter.call();
     }
 
-    protected void onFinishCalled() {
+    void onFinishCalled() {
         mFinishCallCounter.call();
     }
 
-    protected void onPrintJobQueuedCalled() {
+    void onPrintJobQueuedCalled() {
         mPrintJobQueuedCallCounter.call();
     }
 
-    protected void onPrinterDiscoverySessionCreateCalled() {
+    void onPrinterDiscoverySessionCreateCalled() {
         mCreateSessionCallCounter.call();
     }
 
@@ -293,37 +278,37 @@
         mDestroySessionCallCounter.call();
     }
 
-    protected void waitForCancelOperationCallbackCalled() {
+    void waitForCancelOperationCallbackCalled() {
         waitForCallbackCallCount(mCancelOperationCounter, 1,
                 "Did not get expected call to onCancel for the current operation.");
     }
 
-    protected void waitForPrinterDiscoverySessionCreateCallbackCalled() {
+    void waitForPrinterDiscoverySessionCreateCallbackCalled() {
         waitForCallbackCallCount(mCreateSessionCallCounter, 1,
                 "Did not get expected call to onCreatePrinterDiscoverySession.");
     }
 
-    protected void waitForPrinterDiscoverySessionDestroyCallbackCalled(int count) {
+    void waitForPrinterDiscoverySessionDestroyCallbackCalled(int count) {
         waitForCallbackCallCount(mDestroySessionCallCounter, count,
                 "Did not get expected call to onDestroyPrinterDiscoverySession.");
     }
 
-    protected void waitForServiceOnPrintJobQueuedCallbackCalled(int count) {
+    void waitForServiceOnPrintJobQueuedCallbackCalled(int count) {
         waitForCallbackCallCount(mPrintJobQueuedCallCounter, count,
                 "Did not get expected call to onPrintJobQueued.");
     }
 
-    protected void waitForAdapterFinishCallbackCalled() {
+    void waitForAdapterFinishCallbackCalled() {
         waitForCallbackCallCount(mFinishCallCounter, 1,
                 "Did not get expected call to finish.");
     }
 
-    protected void waitForLayoutAdapterCallbackCount(int count) {
+    void waitForLayoutAdapterCallbackCount(int count) {
         waitForCallbackCallCount(mLayoutCallCounter, count,
                 "Did not get expected call to layout.");
     }
 
-    protected void waitForWriteAdapterCallback(int count) {
+    void waitForWriteAdapterCallback(int count) {
         waitForCallbackCallCount(mWriteCallCounter, count, "Did not get expected call to write.");
     }
 
@@ -355,7 +340,7 @@
      *
      * @return The number of onDestroy calls on the print activity.
      */
-    protected static int getActivityDestroyCallbackCallCount() {
+    static int getActivityDestroyCallbackCallCount() {
         return sDestroyActivityCallCounter.getCallCount();
     }
 
@@ -364,7 +349,7 @@
      *
      * @return The number of onCreate calls on the print activity.
      */
-    protected static int getActivityCreateCallbackCallCount() {
+    private static int getActivityCreateCallbackCallCount() {
         return sCreateActivityCallCounter.getCallCount();
     }
 
@@ -381,7 +366,7 @@
     /**
      * Reset all counters.
      */
-    protected void resetCounters() {
+    void resetCounters() {
         mCancelOperationCounter.reset();
         mLayoutCallCounter.reset();
         mWriteCallCounter.reset();
@@ -393,7 +378,7 @@
         sCreateActivityCallCounter.reset();
     }
 
-    protected void selectPrinter(String printerName) throws UiObjectNotFoundException, IOException {
+    void selectPrinter(String printerName) throws UiObjectNotFoundException, IOException {
         try {
             long delay = 100;
             while (true) {
@@ -425,7 +410,6 @@
                     if (delay <= OPERATION_TIMEOUT_MILLIS) {
                         Log.w(LOG_TAG, "Cannot find printer " + printerName + ", retrying.");
                         delay *= 2;
-                        continue;
                     } else {
                         throw new UiObjectNotFoundException("Could find printer " + printerName +
                                 " even though we retried");
@@ -438,19 +422,17 @@
         }
     }
 
-    protected void answerPrintServicesWarning(boolean confirm) throws UiObjectNotFoundException {
-        UiDevice uiDevice = UiDevice.getInstance(getInstrumentation());
+    void answerPrintServicesWarning(boolean confirm) throws UiObjectNotFoundException {
         UiObject button;
         if (confirm) {
-            button = uiDevice.findObject(new UiSelector().resourceId("android:id/button1"));
+            button = mUiDevice.findObject(new UiSelector().resourceId("android:id/button1"));
         } else {
-            button = uiDevice.findObject(new UiSelector().resourceId("android:id/button2"));
+            button = mUiDevice.findObject(new UiSelector().resourceId("android:id/button2"));
         }
         button.click();
     }
 
-    protected void changeOrientation(String orientation)
-            throws UiObjectNotFoundException, IOException {
+    void changeOrientation(String orientation) throws UiObjectNotFoundException, IOException {
         try {
             UiObject orientationSpinner = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/orientation_spinner"));
@@ -474,7 +456,7 @@
         }
     }
 
-    protected void changeMediaSize(String mediaSize) throws UiObjectNotFoundException, IOException {
+    void changeMediaSize(String mediaSize) throws UiObjectNotFoundException, IOException {
         try {
             UiObject mediaSizeSpinner = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/paper_size_spinner"));
@@ -487,18 +469,7 @@
         }
     }
 
-    protected String getMediaSize() throws UiObjectNotFoundException, IOException {
-        try {
-            UiObject mediaSizeSpinner = mUiDevice.findObject(new UiSelector().resourceId(
-                    "com.android.printspooler:id/paper_size_spinner"));
-            return mediaSizeSpinner.getText();
-        } catch (UiObjectNotFoundException e) {
-            dumpWindowHierarchy();
-            throw e;
-        }
-    }
-
-    protected void changeColor(String color) throws UiObjectNotFoundException, IOException {
+    void changeColor(String color) throws UiObjectNotFoundException, IOException {
         try {
             UiObject colorSpinner = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/color_spinner"));
@@ -522,7 +493,7 @@
         }
     }
 
-    protected void changeDuplex(String duplex) throws UiObjectNotFoundException, IOException {
+    void changeDuplex(String duplex) throws UiObjectNotFoundException, IOException {
         try {
             UiObject duplexSpinner = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/duplex_spinner"));
@@ -535,11 +506,11 @@
         }
     }
 
-    protected String getDuplex() throws UiObjectNotFoundException, IOException {
+    void changeCopies(int newCopies) throws UiObjectNotFoundException, IOException {
         try {
-            UiObject duplexSpinner = mUiDevice.findObject(new UiSelector().resourceId(
-                    "com.android.printspooler:id/duplex_spinner"));
-            return duplexSpinner.getText();
+            UiObject copies = mUiDevice.findObject(new UiSelector().resourceId(
+                    "com.android.printspooler:id/copies_edittext"));
+            copies.setText(Integer.valueOf(newCopies).toString());
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
             throw e;
@@ -557,7 +528,7 @@
         }
     }
 
-    protected void clickPrintButton() throws UiObjectNotFoundException, IOException {
+    void clickPrintButton() throws UiObjectNotFoundException, IOException {
         try {
             UiObject printButton = mUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/print_button"));
@@ -568,7 +539,18 @@
         }
     }
 
-    protected void dumpWindowHierarchy() throws IOException {
+    void clickRetryButton() throws UiObjectNotFoundException, IOException {
+        try {
+            UiObject retryButton = mUiDevice.findObject(new UiSelector().resourceId(
+                    "com.android.printspooler:id/action_button"));
+            retryButton.click();
+        } catch (UiObjectNotFoundException e) {
+            dumpWindowHierarchy();
+            throw e;
+        }
+    }
+
+    void dumpWindowHierarchy() throws IOException {
         ByteArrayOutputStream os = new ByteArrayOutputStream();
         mUiDevice.dumpWindowHierarchy(os);
 
@@ -582,7 +564,7 @@
         return sActivity;
     }
 
-    protected void createActivity() {
+    private void createActivity() {
         int createBefore = getActivityCreateCallbackCallCount();
 
         launchActivity(getInstrumentation().getTargetContext().getPackageName(),
@@ -591,26 +573,26 @@
         waitForActivityCreateCallbackCalled(createBefore + 1);
     }
 
-    protected void openPrintOptions() throws UiObjectNotFoundException {
+    void openPrintOptions() throws UiObjectNotFoundException {
         UiObject expandHandle = mUiDevice.findObject(new UiSelector().resourceId(
                 "com.android.printspooler:id/expand_collapse_handle"));
         expandHandle.click();
     }
 
-    protected void openCustomPrintOptions() throws UiObjectNotFoundException {
+    void openCustomPrintOptions() throws UiObjectNotFoundException {
         UiObject expandHandle = mUiDevice.findObject(new UiSelector().resourceId(
                 "com.android.printspooler:id/more_options_button"));
         expandHandle.click();
     }
 
-    protected void clearPrintSpoolerData() throws Exception {
+    void clearPrintSpoolerData() throws Exception {
         assertTrue("failed to clear print spooler data",
                 SystemUtil.runShellCommand(getInstrumentation(), String.format(
                         "pm clear --user %d %s", CURRENT_USER_ID, PRINT_SPOOLER_PACKAGE_NAME))
                         .contains(PM_CLEAR_SUCCESS_OUTPUT));
     }
 
-    protected void verifyLayoutCall(InOrder inOrder, PrintDocumentAdapter mock,
+    void verifyLayoutCall(InOrder inOrder, PrintDocumentAdapter mock,
             PrintAttributes oldAttributes, PrintAttributes newAttributes,
             final boolean forPreview) {
         inOrder.verify(mock).onLayout(eq(oldAttributes), eq(newAttributes),
@@ -630,7 +612,7 @@
                         }));
     }
 
-    protected PrintDocumentAdapter createMockPrintDocumentAdapter(Answer<Void> layoutAnswer,
+    PrintDocumentAdapter createMockPrintDocumentAdapter(Answer<Void> layoutAnswer,
             Answer<Void> writeAnswer, Answer<Void> finishAnswer) {
         // Create a mock print adapter.
         PrintDocumentAdapter adapter = mock(PrintDocumentAdapter.class);
@@ -650,6 +632,49 @@
         return adapter;
     }
 
+    /**
+     * Create a mock {@link PrintDocumentAdapter} that provides one empty page.
+     *
+     * @return The mock adapter
+     */
+    @NonNull PrintDocumentAdapter createDefaultPrintDocumentAdapter(int numPages) {
+        final PrintAttributes[] printAttributes = new PrintAttributes[1];
+
+        return createMockPrintDocumentAdapter(
+                invocation -> {
+                    PrintAttributes oldAttributes = (PrintAttributes) invocation.getArguments()[0];
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    PrintDocumentAdapter.LayoutResultCallback callback =
+                            (PrintDocumentAdapter.LayoutResultCallback) invocation
+                                    .getArguments()[3];
+
+                    callback.onLayoutFinished(new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setPageCount(numPages).build(),
+                            !oldAttributes.equals(printAttributes[0]));
+
+                    oldAttributes = printAttributes[0];
+
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    PrintDocumentAdapter.WriteResultCallback callback =
+                            (PrintDocumentAdapter.WriteResultCallback) args[3];
+
+                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                    fd.close();
+                    callback.onWriteFinished(pages);
+
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    onFinishCalled();
+                    return null;
+                });
+    }
+
     @SuppressWarnings("unchecked")
     protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
             Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
@@ -697,7 +722,7 @@
             Answer<Void> onPrintJobQueued, Answer<Void> onRequestCancelPrintJob) {
         final PrintServiceCallbacks service = mock(PrintServiceCallbacks.class);
 
-        doCallRealMethod().when(service).setService(any(PrintService.class));
+        doCallRealMethod().when(service).setService(any(StubbablePrintService.class));
         when(service.getService()).thenCallRealMethod();
 
         if (onCreatePrinterDiscoverySessionCallbacks != null) {
@@ -725,10 +750,28 @@
         }
         FileOutputStream fos = new FileOutputStream(output.getFileDescriptor());
         document.writeTo(fos);
+        fos.flush();
         document.close();
     }
 
-    protected static final class CallCounter {
+    protected void selectPages(String pages, int totalPages) throws Exception {
+        UiObject pagesSpinner = getUiDevice().findObject(new UiSelector().resourceId(
+                "com.android.printspooler:id/range_options_spinner"));
+        pagesSpinner.click();
+
+        UiObject rangeOption = getUiDevice().findObject(new UiSelector().textContains(
+                getPrintSpoolerStringOneParam("template_page_range", totalPages)));
+        rangeOption.click();
+
+        UiObject pagesEditText = getUiDevice().findObject(new UiSelector().resourceId(
+                "com.android.printspooler:id/page_range_edittext"));
+        pagesEditText.setText(pages);
+
+        // Hide the keyboard.
+        getUiDevice().pressBack();
+    }
+
+    private static final class CallCounter {
         private final Object mLock = new Object();
 
         private int mCallCount;
@@ -740,7 +783,7 @@
             }
         }
 
-        public int getCallCount() {
+        int getCallCount() {
             synchronized (mLock) {
                 return mCallCount;
             }
@@ -779,7 +822,7 @@
      * @param adapter The {@link PrintDocumentAdapter} used
      * @throws Exception If the printer could not be made default
      */
-    protected void makeDefaultPrinter(PrintDocumentAdapter adapter, String printerName)
+    void makeDefaultPrinter(PrintDocumentAdapter adapter, String printerName)
             throws Exception {
         // Perform a full print operation on the printer
         Log.d(LOG_TAG, "print");
@@ -807,4 +850,76 @@
         return getInstrumentation().getContext().getPackageManager()
                 .hasSystemFeature(PackageManager.FEATURE_PRINTING);
     }
+
+    /**
+     * Get a string array from the print spooler's resources.
+     *
+     * @param resourceName The name of the array resource
+     * @return The localized string array
+     *
+     * @throws Exception If anything is unexpected
+     */
+    String[] getPrintSpoolerStringArray(String resourceName) throws Exception {
+        PackageManager pm = getActivity().getPackageManager();
+        Resources printSpoolerRes = pm.getResourcesForApplication(PRINTSPOOLER_PACKAGE);
+        int id = printSpoolerRes.getIdentifier(resourceName, "array", PRINTSPOOLER_PACKAGE);
+        return printSpoolerRes.getStringArray(id);
+    }
+
+    /**
+     * Get a string from the print spooler's resources.
+     *
+     * @param resourceName The name of the string resource
+     * @return The localized string
+     *
+     * @throws Exception If anything is unexpected
+     */
+    String getPrintSpoolerString(String resourceName) throws Exception {
+        PackageManager pm = getActivity().getPackageManager();
+        Resources printSpoolerRes = pm.getResourcesForApplication(PRINTSPOOLER_PACKAGE);
+        int id = printSpoolerRes.getIdentifier(resourceName, "string", PRINTSPOOLER_PACKAGE);
+        return printSpoolerRes.getString(id);
+    }
+
+    /**
+     * Get a string with one parameter from the print spooler's resources.
+     *
+     * @param resourceName The name of the string resource
+     * @return The localized string
+     *
+     * @throws Exception If anything is unexpected
+     */
+    String getPrintSpoolerStringOneParam(String resourceName, Object p)
+            throws Exception {
+        PackageManager pm = getActivity().getPackageManager();
+        Resources printSpoolerRes = pm.getResourcesForApplication(PRINTSPOOLER_PACKAGE);
+        int id = printSpoolerRes.getIdentifier(resourceName, "string", PRINTSPOOLER_PACKAGE);
+        return printSpoolerRes.getString(id, p);
+    }
+
+    /**
+     * Get the default media size for the current locale.
+     *
+     * @return The default media size for the current locale
+     *
+     * @throws Exception If anything is unexpected
+     */
+    PrintAttributes.MediaSize getDefaultMediaSize() throws Exception {
+        PackageManager pm = getActivity().getPackageManager();
+        Resources printSpoolerRes = pm.getResourcesForApplication(PRINTSPOOLER_PACKAGE);
+        int defaultMediaSizeResId = printSpoolerRes.getIdentifier("mediasize_default", "string",
+                PRINTSPOOLER_PACKAGE);
+        String defaultMediaSizeName = printSpoolerRes.getString(defaultMediaSizeResId);
+
+        switch (defaultMediaSizeName) {
+            case "NA_LETTER":
+                return PrintAttributes.MediaSize.NA_LETTER;
+            case "JIS_B5":
+                return PrintAttributes.MediaSize.JIS_B5;
+            case "ISO_A4":
+                return PrintAttributes.MediaSize.ISO_A4;
+            default:
+                throw new Exception("Unknown default media size " + defaultMediaSizeName);
+        }
+    }
 }
diff --git a/tests/tests/print/src/android/print/cts/ClassParametersTest.java b/tests/tests/print/src/android/print/cts/ClassParametersTest.java
index bad47f8..f216dae 100644
--- a/tests/tests/print/src/android/print/cts/ClassParametersTest.java
+++ b/tests/tests/print/src/android/print/cts/ClassParametersTest.java
@@ -24,39 +24,24 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import static android.print.cts.Utils.assertException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 /**
- * Test that the print attributes are correctly propagated through the print framework
+ * Test that the print attributes can be constructed correctly. This does not test that the
+ * attributes have the desired effect when send to the print framework.
  */
 @RunWith(AndroidJUnit4.class)
 public class ClassParametersTest {
     /**
-     * Run a runnable and expect and exception of a certain type.
-     *
-     * @param r The runnable to run
-     * @param expectedClass The expected exception type
-     */
-    private void assertException(Runnable r, Class<? extends RuntimeException> expectedClass) {
-        try {
-            r.run();
-        } catch (Exception e) {
-            if (e.getClass().isAssignableFrom(expectedClass)) {
-                return;
-            } else {
-                throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
-                        + e.getClass().getName());
-            }
-        }
-
-        throw new AssertionError("No exception thrown");
-    }
-
-    /**
-     * Test that we cannot create PrintAttributes with illegal parameters.
+     * Test that we cannot create PrintAttributes.colorModes with illegal parameters.
      *
      * @throws Exception If anything is unexpected
      */
     @Test
-    public void testIllegalPrintAttributes() throws Exception {
+    public void testIllegalPrintAttributesColorMode() throws Throwable {
         assertException(() -> (new PrintAttributes.Builder()).setColorMode(-1),
                 IllegalArgumentException.class);
         assertException(() -> (new PrintAttributes.Builder()).setColorMode(0),
@@ -64,7 +49,15 @@
         assertException(() -> (new PrintAttributes.Builder()).setColorMode(
                 PrintAttributes.COLOR_MODE_COLOR | PrintAttributes.COLOR_MODE_MONOCHROME),
                 IllegalArgumentException.class);
+    }
 
+    /**
+     * Test that we cannot create PrintAttributes.duplexMode with illegal parameters.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    @Test
+    public void testIllegalPrintAttributesDuplexMode() throws Throwable {
         assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(-1),
                 IllegalArgumentException.class);
         assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(0),
@@ -72,7 +65,15 @@
         assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(
                 PrintAttributes.DUPLEX_MODE_LONG_EDGE | PrintAttributes.DUPLEX_MODE_NONE),
                 IllegalArgumentException.class);
+    }
 
+    /**
+     * Test that we cannot create PrintAttributes.resolution with illegal parameters.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    @Test
+    public void testIllegalPrintAttributesResolution() throws Throwable {
         assertException(() -> new Resolution(null, "label", 10, 10),
                 IllegalArgumentException.class);
         assertException(() -> new Resolution("", "label", 10, 10),
@@ -89,7 +90,45 @@
                 IllegalArgumentException.class);
         assertException(() -> new Resolution("id", "label", 10, 0),
                 IllegalArgumentException.class);
+    }
 
+    /**
+     * Test that we can create PrintAttributes.resolution with legal parameters.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    @Test
+    public void testLegalPrintAttributesResolution() throws Exception {
+        // Small resolution
+        Resolution testResolution = new Resolution("testId", "testLabel", 1, 2);
+        assertEquals("testId", testResolution.getId());
+        assertEquals("testLabel", testResolution.getLabel());
+        assertEquals(1, testResolution.getHorizontalDpi());
+        assertEquals(2, testResolution.getVerticalDpi());
+
+        // Small even resolution
+        Resolution testResolution2 = new Resolution("testId2", "testLabel2", 1, 1);
+        assertEquals("testId2", testResolution2.getId());
+        assertEquals("testLabel2", testResolution2.getLabel());
+        assertEquals(1, testResolution2.getHorizontalDpi());
+        assertEquals(1, testResolution2.getVerticalDpi());
+
+        // Large even resolution
+        Resolution testResolution3 = new Resolution("testId3", "testLabel3", Integer.MAX_VALUE,
+                Integer.MAX_VALUE);
+        assertEquals("testId3", testResolution3.getId());
+        assertEquals("testLabel3", testResolution3.getLabel());
+        assertEquals(Integer.MAX_VALUE, testResolution3.getHorizontalDpi());
+        assertEquals(Integer.MAX_VALUE, testResolution3.getVerticalDpi());
+    }
+
+    /**
+     * Test that we cannot create PrintAttributes.mediaSize with illegal parameters.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    @Test
+    public void testIllegalPrintAttributesMediaSize() throws Throwable {
         assertException(() -> new MediaSize(null, "label", 10, 10),
                 IllegalArgumentException.class);
         assertException(() -> new MediaSize("", "label", 10, 10),
@@ -106,8 +145,81 @@
                 IllegalArgumentException.class);
         assertException(() -> new MediaSize("id", "label", 10, 0),
                 IllegalArgumentException.class);
+    }
 
-        // There is no restrictions on what parameters to set for minMargins.
+    /**
+     * Test that we can create PrintAttributes.mediaSize with legal parameters.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    @Test
+    public void testLegalPrintAttributesMediaSize() throws Exception {
+        // Small portrait paper
+        MediaSize testMediaSize1 = new MediaSize("testId", "testLabel", 1, 2);
+        assertEquals("testId", testMediaSize1.getId());
+        assertEquals("testLabel", testMediaSize1.getLabel(null));
+        assertEquals(1, testMediaSize1.getWidthMils());
+        assertEquals(2, testMediaSize1.getHeightMils());
+        assertTrue(testMediaSize1.isPortrait());
+
+        MediaSize testMediaSize1L = testMediaSize1.asLandscape();
+        assertEquals("testId", testMediaSize1L.getId());
+        assertEquals("testLabel", testMediaSize1L.getLabel(null));
+        assertEquals(2, testMediaSize1L.getWidthMils());
+        assertEquals(1, testMediaSize1L.getHeightMils());
+        assertFalse(testMediaSize1L.isPortrait());
+
+        MediaSize testMediaSize1P = testMediaSize1.asPortrait();
+        assertEquals("testId", testMediaSize1P.getId());
+        assertEquals("testLabel", testMediaSize1P.getLabel(null));
+        assertEquals(1, testMediaSize1P.getWidthMils());
+        assertEquals(2, testMediaSize1P.getHeightMils());
+        assertTrue(testMediaSize1P.isPortrait());
+
+        // Small square paper
+        MediaSize testMediaSize2 = new MediaSize("testId2", "testLabel2", 1, 1);
+        assertEquals("testId2", testMediaSize2.getId());
+        assertEquals("testLabel2", testMediaSize2.getLabel(null));
+        assertEquals(1, testMediaSize2.getWidthMils());
+        assertEquals(1, testMediaSize2.getHeightMils());
+        assertTrue(testMediaSize2.isPortrait());
+
+        MediaSize testMediaSize2L = testMediaSize2.asLandscape();
+        assertEquals("testId2", testMediaSize2L.getId());
+        assertEquals("testLabel2", testMediaSize2L.getLabel(null));
+        assertEquals(1, testMediaSize2L.getWidthMils());
+        assertEquals(1, testMediaSize2L.getHeightMils());
+        assertTrue(testMediaSize2L.isPortrait());
+
+        MediaSize testMediaSize2P = testMediaSize2.asPortrait();
+        assertEquals("testId2", testMediaSize2P.getId());
+        assertEquals("testLabel2", testMediaSize2P.getLabel(null));
+        assertEquals(1, testMediaSize2P.getWidthMils());
+        assertEquals(1, testMediaSize2P.getHeightMils());
+        assertTrue(testMediaSize2P.isPortrait());
+
+        // Large landscape paper
+        MediaSize testMediaSize3 = new MediaSize("testId3", "testLabel3", Integer.MAX_VALUE,
+                Integer.MAX_VALUE - 1);
+        assertEquals("testId3", testMediaSize3.getId());
+        assertEquals("testLabel3", testMediaSize3.getLabel(null));
+        assertEquals(Integer.MAX_VALUE, testMediaSize3.getWidthMils());
+        assertEquals(Integer.MAX_VALUE - 1, testMediaSize3.getHeightMils());
+        assertFalse(testMediaSize3.isPortrait());
+
+        MediaSize testMediaSize3L = testMediaSize3.asLandscape();
+        assertEquals("testId3", testMediaSize3L.getId());
+        assertEquals("testLabel3", testMediaSize3L.getLabel(null));
+        assertEquals(Integer.MAX_VALUE, testMediaSize3L.getWidthMils());
+        assertEquals(Integer.MAX_VALUE - 1, testMediaSize3L.getHeightMils());
+        assertFalse(testMediaSize3L.isPortrait());
+
+        MediaSize testMediaSize3P = testMediaSize3.asPortrait();
+        assertEquals("testId3", testMediaSize3P.getId());
+        assertEquals("testLabel3", testMediaSize3P.getLabel(null));
+        assertEquals(Integer.MAX_VALUE - 1, testMediaSize3P.getWidthMils());
+        assertEquals(Integer.MAX_VALUE, testMediaSize3P.getHeightMils());
+        assertTrue(testMediaSize3P.isPortrait());
     }
 
     /**
@@ -116,7 +228,7 @@
      * @throws Exception If anything is unexpected
      */
     @Test
-    public void testIllegalPrintDocumentInfo() throws Exception {
+    public void testIllegalPrintDocumentInfo() throws Throwable {
         assertException(() -> new PrintDocumentInfo.Builder(null),
                 IllegalArgumentException.class);
         assertException(() -> new PrintDocumentInfo.Builder(""),
@@ -124,8 +236,45 @@
 
         assertException(() -> new PrintDocumentInfo.Builder("doc").setPageCount(-2),
                 IllegalArgumentException.class);
-        // -1 == UNKNOWN and 0 are allowed
+    }
 
-        // Content type is not restricted
+    /**
+     * Test that we can create PrintDocumentInfo with legal parameters.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    @Test
+    public void testLegalPrintDocumentInfo() throws Exception {
+        PrintDocumentInfo defaultInfo = new PrintDocumentInfo.Builder("doc").build();
+        assertEquals(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT, defaultInfo.getContentType());
+        assertEquals(PrintDocumentInfo.PAGE_COUNT_UNKNOWN, defaultInfo.getPageCount());
+        assertEquals(0, defaultInfo.getDataSize());
+        assertEquals("doc", defaultInfo.getName());
+
+        PrintDocumentInfo info = new PrintDocumentInfo.Builder("doc")
+                .setContentType(PrintDocumentInfo.CONTENT_TYPE_UNKNOWN).build();
+        assertEquals(PrintDocumentInfo.CONTENT_TYPE_UNKNOWN, info.getContentType());
+
+        PrintDocumentInfo info2 = new PrintDocumentInfo.Builder("doc")
+                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();
+        assertEquals(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT, info2.getContentType());
+
+        PrintDocumentInfo info3 = new PrintDocumentInfo.Builder("doc")
+                .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO).build();
+        assertEquals(PrintDocumentInfo.CONTENT_TYPE_PHOTO, info3.getContentType());
+
+        PrintDocumentInfo info4 = new PrintDocumentInfo.Builder("doc").setContentType(-23).build();
+        assertEquals(-23, info4.getContentType());
+
+        PrintDocumentInfo info5 = new PrintDocumentInfo.Builder("doc").setPageCount(0).build();
+        assertEquals(PrintDocumentInfo.PAGE_COUNT_UNKNOWN, info5.getPageCount());
+
+        PrintDocumentInfo info6 = new PrintDocumentInfo.Builder("doc")
+                .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN).build();
+        assertEquals(PrintDocumentInfo.PAGE_COUNT_UNKNOWN, info6.getPageCount());
+
+        PrintDocumentInfo info7 = new PrintDocumentInfo.Builder("doc")
+                .setPageCount(Integer.MAX_VALUE).build();
+        assertEquals(Integer.MAX_VALUE, info7.getPageCount());
     }
 }
diff --git a/tests/tests/print/src/android/print/cts/CustomPrintOptionsTest.java b/tests/tests/print/src/android/print/cts/CustomPrintOptionsTest.java
index 54b4d23..9dd8bc9 100644
--- a/tests/tests/print/src/android/print/cts/CustomPrintOptionsTest.java
+++ b/tests/tests/print/src/android/print/cts/CustomPrintOptionsTest.java
@@ -49,6 +49,8 @@
 import java.util.List;
 import java.util.concurrent.TimeoutException;
 
+import static android.print.cts.Utils.eventually;
+
 /**
  * This test verifies changes to the printer capabilities are applied correctly.
  */
@@ -87,7 +89,8 @@
      * @throws Exception If something was unexpected
      */
     private PageRange[] getPages() throws Exception {
-        if (getUiDevice().hasObject(By.text("All 3"))) {
+        if (getUiDevice().hasObject(By.text(getPrintSpoolerStringOneParam("template_all_pages",
+                3)))) {
             return PAGESS[2];
         }
 
@@ -344,25 +347,14 @@
                 }
 
                 Log.d(LOG_TAG, "Check pages");
-                while (true) {
-                    try {
-                        PageRange[] actualPages = getPages();
-                        if (!Arrays.equals(newPages, actualPages)) {
-                            new AssertionError(
-                                    "Expected " + Arrays.toString(newPages) + ", actual " +
-                                            Arrays.toString(actualPages));
-                        }
-
-                        break;
-                    } catch (Throwable e) {
-                        if (endTime < System.currentTimeMillis()) {
-                            throw e;
-                        } else {
-                            Log.e(LOG_TAG, "Could not verify pages, retrying", e);
-                            Thread.sleep(100);
-                        }
+                eventually(() -> {
+                    PageRange[] actualPages = getPages();
+                    if (!Arrays.equals(newPages, actualPages)) {
+                        throw new AssertionError(
+                                "Expected " + Arrays.toString(newPages) + ", actual " +
+                                        Arrays.toString(actualPages));
                     }
-                }
+                });
 
                 break;
             } catch (Throwable e) {
@@ -378,13 +370,15 @@
         }
 
         // Abort printing
-        getActivity().finish();
+        getUiDevice().pressBack();
+        getUiDevice().pressBack();
+        getUiDevice().pressBack();
 
         waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
     }
 
-    public void testChangeToChangeEveryThing() throws Throwable {
-        testCase(false, 2, PAGESS[1], MEDIA_SIZES[1], false, COLOR_MODES[1], DUPLEX_MODES[1],
+    public void testChangeToChangeEveryThingButPages() throws Throwable {
+        testCase(false, 2, null, MEDIA_SIZES[1], false, COLOR_MODES[1], DUPLEX_MODES[1],
                 RESOLUTIONS[1]);
     }
 
@@ -427,4 +421,8 @@
     public void testChangeToAllPages() throws Throwable {
         testCase(false, null, PAGESS[2], null, true, null, null, null);
     }
+
+    public void testChangeToSomePages() throws Throwable {
+        testCase(false, null, PAGESS[1], null, true, null, null, null);
+    }
 }
diff --git a/tests/tests/print/src/android/print/cts/InterfaceForAppsTest.java b/tests/tests/print/src/android/print/cts/InterfaceForAppsTest.java
new file mode 100644
index 0000000..d080815
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/InterfaceForAppsTest.java
@@ -0,0 +1,382 @@
+/*
+ * 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.print.cts;
+
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintJob;
+import android.print.PrintJobInfo;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.print.cts.services.FirstPrintService;
+import android.print.cts.services.PrintServiceCallbacks;
+import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.SecondPrintService;
+import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+import static android.print.cts.Utils.eventually;
+import static android.print.cts.Utils.getPrintJob;
+import static android.print.cts.Utils.getPrintManager;
+
+/**
+ * Test interface from the application to the print service.
+ */
+public class InterfaceForAppsTest extends BasePrintTest {
+    private static final String TEST_PRINTER = "Test printer";
+    private static final String LOG_TAG = "InterfaceForAppsTest";
+
+    private static final PrintAttributes.Resolution TWO_HUNDRED_DPI =
+            new PrintAttributes.Resolution("200x200", "200dpi", 200, 200);
+
+    /**
+     * Create a mock {@link PrinterDiscoverySessionCallbacks} that discovers a simple test printer.
+     *
+     * @return The mock session callbacks
+     */
+    private @NonNull PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            StubbablePrinterDiscoverySession session = ((PrinterDiscoverySessionCallbacks) invocation
+                    .getMock()).getSession();
+
+            if (session.getPrinters().isEmpty()) {
+                PrinterId printerId = session.getService().generatePrinterId(TEST_PRINTER);
+                PrinterInfo.Builder printer = new PrinterInfo.Builder(
+                        session.getService().generatePrinterId(TEST_PRINTER), TEST_PRINTER,
+                        PrinterInfo.STATUS_IDLE);
+
+                printer.setCapabilities(new PrinterCapabilitiesInfo.Builder(printerId)
+                        .addMediaSize(PrintAttributes.MediaSize.ISO_A5, true)
+                        .addMediaSize(PrintAttributes.MediaSize.ISO_A3, false)
+                        .addResolution(TWO_HUNDRED_DPI, true)
+                        .setColorModes(PrintAttributes.COLOR_MODE_MONOCHROME
+                                        | PrintAttributes.COLOR_MODE_COLOR,
+                                PrintAttributes.COLOR_MODE_MONOCHROME)
+                        .setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE
+                                        | PrintAttributes.DUPLEX_MODE_LONG_EDGE,
+                                PrintAttributes.DUPLEX_MODE_NONE)
+                        .setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0)).build());
+
+                ArrayList<PrinterInfo> printers = new ArrayList<>(1);
+                printers.add(printer.build());
+
+                session.addPrinters(printers);
+            }
+            return null;
+        }, null, null, invocation -> null, null, null, invocation -> {
+            // Take a note onDestroy was called.
+            onPrinterDiscoverySessionDestroyCalled();
+            return null;
+        });
+    }
+
+    /**
+     * Create mock service callback for a session. Once the job is queued the test function is
+     * called.
+     *
+     * @param sessionCallbacks The callbacks of the session
+     * @param blockAfterState  The state the print services should progress to
+     */
+    private @NonNull PrintServiceCallbacks createFirstMockPrinterServiceCallbacks(
+            final @NonNull PrinterDiscoverySessionCallbacks sessionCallbacks, int blockAfterState) {
+        return createMockPrintServiceCallbacks(
+                invocation -> sessionCallbacks, invocation -> {
+                    android.printservice.PrintJob job = (android.printservice.PrintJob) invocation
+                            .getArguments()[0];
+
+                    switch (blockAfterState) {
+                        case PrintJobInfo.STATE_CREATED:
+                            eventually(() -> assertEquals(PrintJobInfo.STATE_CREATED,
+                                    job.getInfo().getState()));
+                            break;
+                        case PrintJobInfo.STATE_STARTED:
+                            eventually(() -> assertTrue(job.isQueued()));
+                            job.start();
+                            break;
+                        case PrintJobInfo.STATE_QUEUED:
+                            eventually(() -> assertTrue(job.isQueued()));
+                            break;
+                        case PrintJobInfo.STATE_BLOCKED:
+                            eventually(() -> assertTrue(job.isQueued()));
+                            job.start();
+                            job.block("test block");
+                            break;
+                        case PrintJobInfo.STATE_FAILED:
+                            eventually(() -> assertTrue(job.isQueued()));
+                            job.start();
+                            job.fail("test fail");
+                            break;
+                        case PrintJobInfo.STATE_COMPLETED:
+                            eventually(() -> assertTrue(job.isQueued()));
+                            job.start();
+                            job.complete();
+                            break;
+                        default:
+                            throw new Exception("Should not be reached");
+                    }
+
+                    return null;
+                }, invocation -> {
+                    android.printservice.PrintJob job = (android.printservice.PrintJob) invocation
+                            .getArguments()[0];
+
+                    job.cancel();
+                    Log.d(LOG_TAG, "job.cancel()");
+
+                    return null;
+                });
+    }
+
+    /**
+     * Setup mock print subsystem
+     *
+     * @param blockAfterState Tell the print service to block all print jobs at this state
+     *
+     * @return The print document adapter to be used for printing
+     */
+    private @NonNull PrintDocumentAdapter setupPrint(int blockAfterState) {
+        // Create the session of the printers that we will be checking.
+        PrinterDiscoverySessionCallbacks sessionCallbacks = createFirstMockPrinterDiscoverySessionCallbacks();
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
+                sessionCallbacks, blockAfterState);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(serviceCallbacks);
+
+        // We don't use the second service, but we have to still configure it
+        SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+        return createDefaultPrintDocumentAdapter(1);
+    }
+
+    /**
+     * Base test for all cancel print job tests
+     *
+     * @param cancelAfterState The print job state state to progress to canceling
+     * @param printJobName     The print job name to use
+     *
+     * @throws Exception If anything is unexpected
+     */
+    private void cancelPrintJobBaseTest(int cancelAfterState, @NonNull String printJobName)
+            throws Throwable {
+        PrintDocumentAdapter adapter = setupPrint(cancelAfterState);
+
+        print(adapter, printJobName);
+        waitForWriteAdapterCallback(1);
+
+        selectPrinter(TEST_PRINTER);
+        waitForWriteAdapterCallback(2);
+
+        clickPrintButton();
+        answerPrintServicesWarning(true);
+
+        PrintJob job = getPrintJob(getPrintManager(getActivity()), printJobName);
+
+        // Check getState
+        eventually(() -> assertEquals(cancelAfterState, job.getInfo().getState()));
+
+        // Check
+        switch (cancelAfterState) {
+            case PrintJobInfo.STATE_QUEUED:
+                assertTrue(job.isQueued());
+                break;
+            case PrintJobInfo.STATE_STARTED:
+                assertTrue(job.isStarted());
+                break;
+            case PrintJobInfo.STATE_BLOCKED:
+                assertTrue(job.isBlocked());
+                break;
+            case PrintJobInfo.STATE_COMPLETED:
+                assertTrue(job.isCompleted());
+                break;
+            case PrintJobInfo.STATE_FAILED:
+                assertTrue(job.isFailed());
+                break;
+            case PrintJobInfo.STATE_CANCELED:
+                assertTrue(job.isCancelled());
+                break;
+        }
+
+        job.cancel();
+        eventually(() -> assertTrue(job.isCancelled()));
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
+    public void testAttemptCancelCreatedPrintJob() throws Throwable {
+        PrintDocumentAdapter adapter = setupPrint(PrintJobInfo.STATE_STARTED);
+
+        print(adapter, "testAttemptCancelCreatedPrintJob");
+        waitForWriteAdapterCallback(1);
+
+        selectPrinter(TEST_PRINTER);
+        waitForWriteAdapterCallback(2);
+
+        PrintJob job = getPrintJob(getPrintManager(getActivity()),
+                "testAttemptCancelCreatedPrintJob");
+
+        // Cancel does not have an effect on created jobs
+        job.cancel();
+        eventually(() -> assertEquals(PrintJobInfo.STATE_CREATED, job.getInfo().getState()));
+
+        // Cancel printing by exiting print activity
+        getUiDevice().pressBack();
+        eventually(() -> assertTrue(job.isCancelled()));
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
+    public void testCancelStartedPrintJob() throws Throwable {
+        cancelPrintJobBaseTest(PrintJobInfo.STATE_STARTED, "testCancelStartedPrintJob");
+    }
+
+    public void testCancelBlockedPrintJob() throws Throwable {
+        cancelPrintJobBaseTest(PrintJobInfo.STATE_BLOCKED, "testCancelBlockedPrintJob");
+    }
+
+    public void testCancelFailedPrintJob() throws Throwable {
+        cancelPrintJobBaseTest(PrintJobInfo.STATE_FAILED, "testCancelFailedPrintJob");
+    }
+
+    public void testRestartFailedPrintJob() throws Throwable {
+        PrintDocumentAdapter adapter = setupPrint(PrintJobInfo.STATE_FAILED);
+
+        print(adapter, "testRestartFailedPrintJob");
+        waitForWriteAdapterCallback(1);
+
+        selectPrinter(TEST_PRINTER);
+        waitForWriteAdapterCallback(2);
+
+        clickPrintButton();
+        answerPrintServicesWarning(true);
+
+        PrintJob job = getPrintJob(getPrintManager(getActivity()), "testRestartFailedPrintJob");
+
+        eventually(() -> assertTrue(job.isFailed()));
+
+        // Restart goes from failed right to queued, so stop the print job at "queued" now
+        setupPrint(PrintJobInfo.STATE_QUEUED);
+
+        job.restart();
+        eventually(() -> assertTrue(job.isQueued()));
+
+        job.cancel();
+        eventually(() -> assertTrue(job.isCancelled()));
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
+    public void testGetTwoPrintJobStates() throws Throwable {
+        PrintDocumentAdapter adapter = setupPrint(PrintJobInfo.STATE_BLOCKED);
+        print(adapter, "testGetTwoPrintJobStates-block");
+        waitForWriteAdapterCallback(1);
+
+        selectPrinter(TEST_PRINTER);
+        waitForWriteAdapterCallback(2);
+
+        clickPrintButton();
+        answerPrintServicesWarning(true);
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+
+        PrintJob job1 = getPrintJob(getPrintManager(getActivity()),
+                "testGetTwoPrintJobStates-block");
+        eventually(() -> assertTrue(job1.isBlocked()));
+
+        adapter = setupPrint(PrintJobInfo.STATE_COMPLETED);
+        print(adapter, "testGetTwoPrintJobStates-complete");
+        waitForWriteAdapterCallback(3);
+        clickPrintButton();
+
+        PrintJob job2 = getPrintJob(getPrintManager(getActivity()),
+                "testGetTwoPrintJobStates-complete");
+        eventually(() -> assertTrue(job2.isCompleted()));
+
+        // Ids have to be unique
+        assertFalse(job1.getId().equals(job2.getId()));
+        assertFalse(job1.equals(job2));
+
+        // Ids have to be the same in job and info and if we find the same job again
+        assertEquals(job1.getId(), job1.getInfo().getId());
+        assertEquals(job1.getId(),
+                getPrintJob(getPrintManager(getActivity()),
+                        "testGetTwoPrintJobStates-block").getId());
+        assertEquals(job1, getPrintJob(getPrintManager(getActivity()),
+                "testGetTwoPrintJobStates-block"));
+        assertEquals(job2.getId(), job2.getInfo().getId());
+        assertEquals(job2.getId(), getPrintJob(getPrintManager(getActivity()),
+                "testGetTwoPrintJobStates-complete").getId());
+        assertEquals(job2, getPrintJob(getPrintManager(getActivity()),
+                "testGetTwoPrintJobStates-complete"));
+
+        // First print job should still be there
+        PrintJob job1again = getPrintJob(getPrintManager(getActivity()),
+                "testGetTwoPrintJobStates-block");
+        assertTrue(job1again.isBlocked());
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(2);
+    }
+
+    public void testChangedPrintJobInfo() throws Throwable {
+        PrintDocumentAdapter adapter = setupPrint(PrintJobInfo.STATE_COMPLETED);
+        long beforeStart = System.currentTimeMillis();
+        print(adapter, "testPrintJobInfo");
+        waitForWriteAdapterCallback(1);
+        long afterStart = System.currentTimeMillis();
+
+        selectPrinter(TEST_PRINTER);
+        waitForWriteAdapterCallback(2);
+
+        PrintJob job = getPrintJob(getPrintManager(getActivity()), "testPrintJobInfo");
+
+        // Set some non default options
+        openPrintOptions();
+        changeCopies(2);
+        changeColor(getPrintSpoolerStringArray("color_mode_labels")[1]);
+        // Leave duplex as default to test that defaults are retained
+        changeMediaSize(
+                PrintAttributes.MediaSize.ISO_A3.getLabel(getActivity().getPackageManager()));
+        changeOrientation(getPrintSpoolerStringArray("orientation_labels")[1]);
+
+        // Print and wait until it is completed
+        clickPrintButton();
+        answerPrintServicesWarning(true);
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+        eventually(job::isCompleted);
+
+        // Make sure all options were applied
+        assertEquals(TEST_PRINTER, job.getInfo().getPrinterId().getLocalId());
+        assertEquals(2, job.getInfo().getCopies());
+        assertEquals(PrintAttributes.COLOR_MODE_COLOR,
+                job.getInfo().getAttributes().getColorMode());
+        assertEquals(PrintAttributes.DUPLEX_MODE_NONE,
+                job.getInfo().getAttributes().getDuplexMode());
+        assertEquals(PrintAttributes.MediaSize.ISO_A3.asLandscape(),
+                job.getInfo().getAttributes().getMediaSize());
+        assertEquals(TWO_HUNDRED_DPI, job.getInfo().getAttributes().getResolution());
+
+        // Check creation time with 5 sec jitter allowance
+        assertTrue(beforeStart - 5000 <= job.getInfo().getCreationTime());
+        assertTrue(job.getInfo().getCreationTime() <= afterStart + 5000);
+    }
+}
diff --git a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
index df142b9..5d7ff3a 100644
--- a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
+++ b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
@@ -41,13 +41,8 @@
 import android.print.cts.services.StubbablePrinterDiscoverySession;
 import android.printservice.PrintJob;
 import android.printservice.PrintService;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
 
 import org.mockito.InOrder;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -70,68 +65,22 @@
 
         // Create a callback for the target print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-            new Answer<PrinterDiscoverySessionCallbacks>() {
-            @Override
-            public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                    return createMockFirstPrinterDiscoverySessionCallbacks();
-                }
-            },
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                PrintJob printJob = (PrintJob) invocation.getArguments()[0];
-                PageRange[] pages = printJob.getInfo().getPages();
-                assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
-                printJob.complete();
-                onPrintJobQueuedCalled();
-                return null;
-            }
-        }, null);
-
-        final PrintAttributes[] printAttributes = new PrintAttributes[1];
+                invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
+                invocation -> {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                    PageRange[] pages = printJob.getInfo().getPages();
+                    assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
+                    printJob.complete();
+                    onPrintJobQueuedCalled();
+                    return null;
+                }, null);
 
         // Configure the print services.
         FirstPrintService.setCallbacks(firstServiceCallbacks);
         SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
 
         // Create a mock print adapter.
-        final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(PAGE_COUNT)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, 0, PAGE_COUNT - 1);
-                fd.close();
-                callback.onWriteFinished(pages);
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+        final PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(PAGE_COUNT);
 
         // Start printing.
         print(adapter);
@@ -176,25 +125,17 @@
 
         // Create a callback for the target print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-            new Answer<PrinterDiscoverySessionCallbacks>() {
-            @Override
-            public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                    return createMockFirstPrinterDiscoverySessionCallbacks();
-                }
-            },
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                PrintJob printJob = (PrintJob) invocation.getArguments()[0];
-                PageRange[] pages = printJob.getInfo().getPages();
-                // We asked for some pages, the app wrote more, but the system
-                // pruned extra pages, hence we expect to print all pages.
-                assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
-                printJob.complete();
-                onPrintJobQueuedCalled();
-                return null;
-            }
-        }, null);
+                invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
+                invocation -> {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                    PageRange[] pages = printJob.getInfo().getPages();
+                    // We asked for some pages, the app wrote more, but the system
+                    // pruned extra pages, hence we expect to print all pages.
+                    assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
+                    printJob.complete();
+                    onPrintJobQueuedCalled();
+                    return null;
+                }, null);
 
         final PrintAttributes[] printAttributes = new PrintAttributes[1];
 
@@ -204,43 +145,34 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(PAGE_COUNT)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                assertTrue(pages[pages.length - 1].getEnd() < PAGE_COUNT);
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, 0, PAGE_COUNT - 1);
-                fd.close();
-                callback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(PAGE_COUNT)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    assertTrue(pages[pages.length - 1].getEnd() < PAGE_COUNT);
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(printAttributes[0], fd, 0, PAGE_COUNT - 1);
+                    fd.close();
+                    callback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -258,7 +190,7 @@
         waitForLayoutAdapterCallbackCount(2);
 
         // Select only the second page.
-        selectPages("2");
+        selectPages("2", PAGE_COUNT);
 
         // Click the print button.
         clickPrintButton();
@@ -293,28 +225,20 @@
 
         // Create a callback for the target print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-            new Answer<PrinterDiscoverySessionCallbacks>() {
-            @Override
-            public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                    return createMockFirstPrinterDiscoverySessionCallbacks();
-                }
-            },
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                PrintJob printJob = (PrintJob) invocation.getArguments()[0];
-                PrintJobInfo printJobInfo = printJob.getInfo();
-                PageRange[] pages = printJobInfo.getPages();
-                // We asked only for page 55 (index 54) but got 55 and 56 (indices
-                // 54, 55), but the system pruned the extra page, hence we expect
-                // to print all pages.
-                assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
-                assertSame(printJob.getDocument().getInfo().getPageCount(), 1);
-                printJob.complete();
-                onPrintJobQueuedCalled();
-                return null;
-            }
-        }, null);
+                invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
+                invocation -> {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                    PrintJobInfo printJobInfo = printJob.getInfo();
+                    PageRange[] pages = printJobInfo.getPages();
+                    // We asked only for page 55 (index 54) but got 55 and 56 (indices
+                    // 54, 55), but the system pruned the extra page, hence we expect
+                    // to print all pages.
+                    assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
+                    assertSame(printJob.getDocument().getInfo().getPageCount(), 1);
+                    printJob.complete();
+                    onPrintJobQueuedCalled();
+                    return null;
+                }, null);
 
         final PrintAttributes[] printAttributes = new PrintAttributes[1];
 
@@ -324,57 +248,48 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(PAGE_COUNT)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                // We expect a single range as it is either the pages for
-                // preview or the page we selected in the UI.
-                assertSame(pages.length, 1);
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(PAGE_COUNT)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    // We expect a single range as it is either the pages for
+                    // preview or the page we selected in the UI.
+                    assertSame(pages.length, 1);
 
-                // The first write request for some pages to preview.
-                if (getWriteCallCount() == 0) {
-                    // Write all requested pages.
-                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                    callback.onWriteFinished(pages);
-                } else {
-                    // Otherwise write a page more that the one we selected.
-                    writeBlankPages(printAttributes[0], fd, REQUESTED_PAGE - 1, REQUESTED_PAGE);
-                    callback.onWriteFinished(new PageRange[] {new PageRange(REQUESTED_PAGE - 1,
-                            REQUESTED_PAGE)});
-                }
+                    // The first write request for some pages to preview.
+                    if (getWriteCallCount() == 0) {
+                        // Write all requested pages.
+                        writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                        callback.onWriteFinished(pages);
+                    } else {
+                        // Otherwise write a page more that the one we selected.
+                        writeBlankPages(printAttributes[0], fd, REQUESTED_PAGE - 1, REQUESTED_PAGE);
+                        callback.onWriteFinished(new PageRange[] {new PageRange(REQUESTED_PAGE - 1,
+                                REQUESTED_PAGE)});
+                    }
 
-                fd.close();
+                    fd.close();
 
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -392,7 +307,7 @@
         waitForLayoutAdapterCallbackCount(2);
 
         // Select a page not written for preview.
-        selectPages(Integer.valueOf(REQUESTED_PAGE).toString());
+        selectPages(Integer.valueOf(REQUESTED_PAGE).toString(), PAGE_COUNT);
 
         // Click the print button.
         clickPrintButton();
@@ -425,12 +340,7 @@
 
         // Create a callback for the target print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-            new Answer<PrinterDiscoverySessionCallbacks>() {
-            @Override
-            public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                    return createMockFirstPrinterDiscoverySessionCallbacks();
-                }
-            },
+                invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
             null, null);
 
         final PrintAttributes[] printAttributes = new PrintAttributes[1];
@@ -441,49 +351,40 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(PAGE_COUNT)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                assertSame(pages.length, 1);
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(PAGE_COUNT)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    assertSame(pages.length, 1);
 
-                // We should be asked for some pages...
-                assertSame(pages[0].getStart(), 0);
-                assertTrue(pages[0].getEnd() == MAX_PREVIEW_PAGES_BATCH - 1);
+                    // We should be asked for some pages...
+                    assertSame(pages[0].getStart(), 0);
+                    assertTrue(pages[0].getEnd() == MAX_PREVIEW_PAGES_BATCH - 1);
 
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                fd.close();
-                callback.onWriteFinished(new PageRange[]{new PageRange(1, 1)});
+                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                    fd.close();
+                    callback.onWriteFinished(new PageRange[]{new PageRange(1, 1)});
 
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -517,28 +418,20 @@
 
         // Create a callback for the target print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-            new Answer<PrinterDiscoverySessionCallbacks>() {
-            @Override
-            public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                return createMockFirstPrinterDiscoverySessionCallbacks();
-                    }
-            }, new Answer<Void>() {
-            @Override
-                public Void answer(InvocationOnMock invocation) {
-                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
-                    PrintJobInfo printJobInfo = printJob.getInfo();
-                    PageRange[] pages = printJobInfo.getPages();
-                    // We asked only for page 3 (index 2) but got this page when
-                    // we were getting the pages for preview (indices 0 - 49),
-                    // but the framework pruned extra pages, hence we should be asked
-                    // to print all pages from a single page document.
-                    assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
-                    assertSame(printJob.getDocument().getInfo().getPageCount(), 1);
-                    printJob.complete();
-                    onPrintJobQueuedCalled();
-                    return null;
-                }
-            }, null);
+                invocation -> createMockFirstPrinterDiscoverySessionCallbacks(), invocation -> {
+                        PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                        PrintJobInfo printJobInfo = printJob.getInfo();
+                        PageRange[] pages = printJobInfo.getPages();
+                        // We asked only for page 3 (index 2) but got this page when
+                        // we were getting the pages for preview (indices 0 - 49),
+                        // but the framework pruned extra pages, hence we should be asked
+                        // to print all pages from a single page document.
+                        assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
+                        assertSame(printJob.getDocument().getInfo().getPageCount(), 1);
+                        printJob.complete();
+                        onPrintJobQueuedCalled();
+                        return null;
+                    }, null);
 
         final PrintAttributes[] printAttributes = new PrintAttributes[1];
 
@@ -548,48 +441,39 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(PAGE_COUNT)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                // We expect a single range as it is either the pages for
-                // preview or the page we selected in the UI.
-                assertSame(pages.length, 1);
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(PAGE_COUNT)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    // We expect a single range as it is either the pages for
+                    // preview or the page we selected in the UI.
+                    assertSame(pages.length, 1);
 
-                // Write all requested pages.
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                callback.onWriteFinished(pages);
-                fd.close();
+                    // Write all requested pages.
+                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                    callback.onWriteFinished(pages);
+                    fd.close();
 
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -607,7 +491,7 @@
         waitForLayoutAdapterCallbackCount(2);
 
         // Select a page not written for preview.
-        selectPages("3");
+        selectPages("3", PAGE_COUNT);
 
         // Click the print button.
         clickPrintButton();
@@ -633,57 +517,38 @@
                 any(PrintJob.class));
     }
 
-    private void selectPages(String pages) throws UiObjectNotFoundException {
-        UiObject pagesSpinner = getUiDevice().findObject(new UiSelector().resourceId(
-                "com.android.printspooler:id/range_options_spinner"));
-        pagesSpinner.click();
-
-        UiObject rangeOption = getUiDevice().findObject(new UiSelector().textContains("Range"));
-        rangeOption.click();
-
-        UiObject pagesEditText = getUiDevice().findObject(new UiSelector().resourceId(
-                "com.android.printspooler:id/page_range_edittext"));
-        pagesEditText.setText(pages);
-
-        // Hide the keyboard.
-        getUiDevice().pressBack();
-    }
-
     private PrinterDiscoverySessionCallbacks createMockFirstPrinterDiscoverySessionCallbacks() {
-        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                PrinterDiscoverySessionCallbacks mock = (PrinterDiscoverySessionCallbacks)
-                        invocation.getMock();
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            PrinterDiscoverySessionCallbacks mock = (PrinterDiscoverySessionCallbacks)
+                    invocation.getMock();
 
-                StubbablePrinterDiscoverySession session = mock.getSession();
-                PrintService service = session.getService();
+            StubbablePrinterDiscoverySession session = mock.getSession();
+            PrintService service = session.getService();
 
-                if (session.getPrinters().isEmpty()) {
-                          List<PrinterInfo> printers = new ArrayList<>();
+            if (session.getPrinters().isEmpty()) {
+                      List<PrinterInfo> printers = new ArrayList<>();
 
-                    // Add one printer.
-                    PrinterId firstPrinterId = service.generatePrinterId("first_printer");
-                    PrinterCapabilitiesInfo firstCapabilities =
-                            new PrinterCapabilitiesInfo.Builder(firstPrinterId)
-                        .setMinMargins(new Margins(200, 200, 200, 200))
-                        .addMediaSize(MediaSize.ISO_A4, true)
-                        .addMediaSize(MediaSize.ISO_A5, false)
-                        .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
-                        .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                PrintAttributes.COLOR_MODE_COLOR)
-                        .build();
-                    PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
-                            FIRST_PRINTER, PrinterInfo.STATUS_IDLE)
-                        .setCapabilities(firstCapabilities)
-                        .build();
-                    printers.add(firstPrinter);
+                // Add one printer.
+                PrinterId firstPrinterId = service.generatePrinterId("first_printer");
+                PrinterCapabilitiesInfo firstCapabilities =
+                        new PrinterCapabilitiesInfo.Builder(firstPrinterId)
+                    .setMinMargins(new Margins(200, 200, 200, 200))
+                    .addMediaSize(MediaSize.ISO_A4, true)
+                    .addMediaSize(MediaSize.ISO_A5, false)
+                    .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                            PrintAttributes.COLOR_MODE_COLOR)
+                    .build();
+                PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
+                        FIRST_PRINTER, PrinterInfo.STATUS_IDLE)
+                    .setCapabilities(firstCapabilities)
+                    .build();
+                printers.add(firstPrinter);
 
-                    session.addPrinters(printers);
-                }
-
-                return null;
+                session.addPrinters(printers);
             }
+
+            return null;
         }, null, null, null, null, null, null);
     }
 
diff --git a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
index 5459c31..0700e7c 100644
--- a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
@@ -37,8 +37,6 @@
 import android.printservice.PrintJob;
 
 import android.util.Log;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -140,73 +138,62 @@
             final MediaSize defaultMediaSize, final int colorModes[], final int defaultColorMode,
             final int duplexModes[], final int defaultDuplexMode, final Resolution resolutions[],
             final Resolution defaultResolution) {
-        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                StubbablePrinterDiscoverySession session =
-                        ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            StubbablePrinterDiscoverySession session =
+                    ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
 
-                if (session.getPrinters().isEmpty()) {
-                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
-                    PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
+            if (session.getPrinters().isEmpty()) {
+                List<PrinterInfo> printers = new ArrayList<>();
+                PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
 
-                    PrinterCapabilitiesInfo.Builder builder =
-                            new PrinterCapabilitiesInfo.Builder(printerId);
+                PrinterCapabilitiesInfo.Builder builder =
+                        new PrinterCapabilitiesInfo.Builder(printerId);
 
-                    builder.setMinMargins(minMargins);
+                builder.setMinMargins(minMargins);
 
-                    int mediaSizesLength = mediaSizes.length;
-                    for (int i = 0; i < mediaSizesLength; i++) {
-                        if (mediaSizes[i].equals(defaultMediaSize)) {
-                            builder.addMediaSize(mediaSizes[i], true);
-                        } else {
-                            builder.addMediaSize(mediaSizes[i], false);
-                        }
+                int mediaSizesLength = mediaSizes.length;
+                for (int i = 0; i < mediaSizesLength; i++) {
+                    if (mediaSizes[i].equals(defaultMediaSize)) {
+                        builder.addMediaSize(mediaSizes[i], true);
+                    } else {
+                        builder.addMediaSize(mediaSizes[i], false);
                     }
-
-                    int colorModesMask = 0;
-                    int colorModesLength = colorModes.length;
-                    for (int i = 0; i < colorModesLength; i++) {
-                        colorModesMask |= colorModes[i];
-                    }
-                    builder.setColorModes(colorModesMask, defaultColorMode);
-
-                    int duplexModesMask = 0;
-                    int duplexModeLength = duplexModes.length;
-                    for (int i = 0; i < duplexModeLength; i++) {
-                        duplexModesMask |= duplexModes[i];
-                    }
-                    builder.setDuplexModes(duplexModesMask, defaultDuplexMode);
-
-                    int resolutionsLength = resolutions.length;
-                    for (int i = 0; i < resolutionsLength; i++) {
-                        if (resolutions[i].equals(defaultResolution)) {
-                            builder.addResolution(resolutions[i], true);
-                        } else {
-                            builder.addResolution(resolutions[i], false);
-                        }
-                    }
-
-                    PrinterInfo printer = new PrinterInfo.Builder(printerId, PRINTER_NAME,
-                            PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build();
-                    printers.add(printer);
-
-                    session.addPrinters(printers);
                 }
-                return null;
+
+                int colorModesMask = 0;
+                int colorModesLength = colorModes.length;
+                for (int i = 0; i < colorModesLength; i++) {
+                    colorModesMask |= colorModes[i];
+                }
+                builder.setColorModes(colorModesMask, defaultColorMode);
+
+                int duplexModesMask = 0;
+                int duplexModeLength = duplexModes.length;
+                for (int i = 0; i < duplexModeLength; i++) {
+                    duplexModesMask |= duplexModes[i];
+                }
+                builder.setDuplexModes(duplexModesMask, defaultDuplexMode);
+
+                int resolutionsLength = resolutions.length;
+                for (int i = 0; i < resolutionsLength; i++) {
+                    if (resolutions[i].equals(defaultResolution)) {
+                        builder.addResolution(resolutions[i], true);
+                    } else {
+                        builder.addResolution(resolutions[i], false);
+                    }
+                }
+
+                PrinterInfo printer = new PrinterInfo.Builder(printerId, PRINTER_NAME,
+                        PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build();
+                printers.add(printer);
+
+                session.addPrinters(printers);
             }
-        }, null, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                return null;
-            }
-        }, null, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Take a note onDestroy was called.
-                onPrinterDiscoverySessionDestroyCalled();
-                return null;
-            }
+            return null;
+        }, null, null, invocation -> null, null, null, invocation -> {
+            // Take a note onDestroy was called.
+            onPrinterDiscoverySessionDestroyCalled();
+            return null;
         });
     }
 
@@ -229,43 +216,34 @@
      */
     private PrintDocumentAdapter createMockPrintDocumentAdapter() {
         return createMockPrintDocumentAdapter(
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        mLayoutAttributes = (PrintAttributes) invocation.getArguments()[1];
-                        LayoutResultCallback callback =
-                                (LayoutResultCallback) invocation.getArguments()[3];
-                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                                .setPageCount(1)
-                                .build();
-                        callback.onLayoutFinished(info, false);
-                        // Mark layout was called.
-                        onLayoutCalled();
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        Object[] args = invocation.getArguments();
-                        PageRange[] pages = (PageRange[]) args[0];
-                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                        WriteResultCallback callback = (WriteResultCallback) args[3];
-                        writeBlankPages(mLayoutAttributes, fd, pages[0].getStart(),
-                                pages[0].getEnd());
-                        fd.close();
-                        callback.onWriteFinished(pages);
-                        // Mark write was called.
-                        onWriteCalled();
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        // Mark finish was called.
-                        onFinishCalled();
-                        return null;
-                    }
+                invocation -> {
+                    mLayoutAttributes = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback =
+                            (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(1)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(mLayoutAttributes, fd, pages[0].getStart(),
+                            pages[0].getEnd());
+                    fd.close();
+                    callback.onWriteFinished(pages);
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
                 });
     }
 
@@ -293,20 +271,12 @@
                         defaultDuplexMode, resolutions, defaultResolution);
 
         PrintServiceCallbacks serviceCallbacks = createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return sessionCallbacks;
-                    }
-                },
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        PrintJob printJob = (PrintJob) invocation.getArguments()[0];
-                        // We pretend the job is handled immediately.
-                        printJob.complete();
-                        return null;
-                    }
+                invocation -> sessionCallbacks,
+                invocation -> {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                    // We pretend the job is handled immediately.
+                    printJob.complete();
+                    return null;
                 }, null);
 
         // Configure the print services.
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
index f171884..37a86fb 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
@@ -16,13 +16,13 @@
 
 package android.print.cts;
 
+import static android.print.cts.Utils.eventually;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 import android.os.CancellationSignal;
-import android.os.CancellationSignal.OnCancelListener;
 import android.os.ParcelFileDescriptor;
 import android.print.PageRange;
 import android.print.PrintAttributes;
@@ -43,11 +43,11 @@
 import android.print.cts.services.StubbablePrinterDiscoverySession;
 import android.printservice.PrintJob;
 import android.printservice.PrintService;
+import android.util.Log;
 
 import org.mockito.InOrder;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -58,6 +58,8 @@
  */
 public class PrintDocumentAdapterContractTest extends BasePrintTest {
 
+    private static final String LOG_TAG = "PrintDocumentAdapterContractTest";
+
     public void testNoPrintOptionsOrPrinterChange() throws Exception {
         if (!supportsPrinting()) {
             return;
@@ -70,42 +72,33 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(2)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                fd.close();
-                callback.onWriteFinished(pages);
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(2)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                    fd.close();
+                    callback.onWriteFinished(pages);
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -141,7 +134,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
@@ -190,45 +183,8 @@
         FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
         SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
 
-        final PrintAttributes[] printAttributes = new PrintAttributes[1];
-
         // Create a mock print adapter.
-        final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback)
-                        invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                    .setPageCount(1)
-                    .build();
-                callback.onLayoutFinished(info, false);
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                fd.close();
-                callback.onWriteFinished(pages);
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
         // Start printing.
         print(adapter);
@@ -256,7 +212,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
@@ -276,6 +232,77 @@
         verifyNoMoreInteractions(adapter);
     }
 
+    public void testNonCallingBackWrite() throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        final PrintAttributes[] printAttributes = new PrintAttributes[1];
+        final boolean[] isWriteBroken = new boolean[1];
+
+        // Create a mock print adapter.
+        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    PrintDocumentAdapter.LayoutResultCallback callback =
+                            (PrintDocumentAdapter.LayoutResultCallback) invocation
+                                    .getArguments()[3];
+
+                    callback.onLayoutFinished(new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                                    .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN).build(),
+                            false);
+
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PrintDocumentAdapter.WriteResultCallback callback =
+                            (PrintDocumentAdapter.WriteResultCallback) args[3];
+
+                    if (isWriteBroken[0]) {
+                        ((CancellationSignal) args[2])
+                                .setOnCancelListener(() -> callback.onWriteCancelled());
+                    } else {
+                        try (ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1]) {
+                            writeBlankPages(printAttributes[0], fd, 0, 1);
+                        }
+                        callback.onWriteFinished(new PageRange[]{new PageRange(0, 0)});
+                    }
+
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    onFinishCalled();
+                    return null;
+                });
+
+        // never return from writes until we repair the write call later
+        isWriteBroken[0] = true;
+
+        // Start printing.
+        print(adapter);
+
+        // Wait for write. This will happen as the the first layout always triggers a write
+        waitForWriteAdapterCallback(1);
+
+        // Finally return useful data from the adapter's write call
+        isWriteBroken[0] = false;
+
+        selectPrinter("Third printer");
+        clickPrintButton();
+        answerPrintServicesWarning(true);
+
+        // The layout reports that the doc did not change and none of the print attributes changed.
+        // Still: As the pages are not written yet we still get a write call
+        waitForWriteAdapterCallback(2);
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
     public void testPrintOptionsChangeAndNoPrinterChange() throws Exception {
         if (!supportsPrinting()) {
             return;
@@ -288,43 +315,34 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback)
-                        invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                    .setPageCount(1)
-                    .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                fd.close();
-                callback.onWriteFinished(pages);
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback)
+                            invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                        .setPageCount(1)
+                        .build();
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                    fd.close();
+                    callback.onWriteFinished(pages);
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -342,25 +360,25 @@
         waitForLayoutAdapterCallbackCount(2);
 
         // Change the orientation.
-        changeOrientation("Landscape");
+        changeOrientation(getPrintSpoolerStringArray("orientation_labels")[1]);
 
         // Wait for layout.
         waitForLayoutAdapterCallbackCount(3);
 
         // Change the media size.
-        changeMediaSize("ISO A4");
+        changeMediaSize(MediaSize.ISO_A0.getLabel(getActivity().getPackageManager()));
 
         // Wait for layout.
         waitForLayoutAdapterCallbackCount(4);
 
         // Change the color.
-        changeColor("Black & White");
+        changeColor(getPrintSpoolerStringArray("color_mode_labels")[0]);
 
         // Wait for layout.
         waitForLayoutAdapterCallbackCount(5);
 
         // Change the duplex.
-        changeDuplex("Short edge");
+        changeDuplex(getPrintSpoolerStringArray("duplex_mode_labels")[2]);
 
         // Wait for layout.
         waitForLayoutAdapterCallbackCount(6);
@@ -387,7 +405,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
@@ -432,7 +450,7 @@
         // there shouldn't be a next call to write.
         PrintAttributes fourthOldAttributes = thirdNewAttributes;
         PrintAttributes fourthNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.ISO_A4.asLandscape())
+                .setMediaSize(MediaSize.ISO_A0.asLandscape())
                 .setResolution(new Resolution("300x300", "300x300", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
@@ -445,7 +463,7 @@
         // there shouldn't be a next call to write.
         PrintAttributes fifthOldAttributes = fourthNewAttributes;
         PrintAttributes fifthNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.ISO_A4.asLandscape())
+                .setMediaSize(MediaSize.ISO_A0.asLandscape())
                 .setResolution(new Resolution("300x300", "300x300", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME)
@@ -458,7 +476,7 @@
         // there shouldn't be a next call to write.
         PrintAttributes sixthOldAttributes = fifthNewAttributes;
         PrintAttributes sixthNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.ISO_A4.asLandscape())
+                .setMediaSize(MediaSize.ISO_A0.asLandscape())
                 .setResolution(new Resolution("300x300", "300x300", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME)
@@ -492,43 +510,34 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback)
-                        invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                    .setPageCount(1)
-                    .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                fd.close();
-                callback.onWriteFinished(pages);
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback)
+                            invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                        .setPageCount(1)
+                        .build();
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                    fd.close();
+                    callback.onWriteFinished(pages);
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -546,7 +555,7 @@
         waitForLayoutAdapterCallbackCount(2);
 
         // Change the color.
-        changeColor("Black & White");
+        changeColor(getPrintSpoolerStringArray("color_mode_labels")[0]);
 
         // Wait for layout.
         waitForLayoutAdapterCallbackCount(3);
@@ -580,7 +589,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS)
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
@@ -622,7 +631,7 @@
         // new printer which results in a layout pass. Same for color.
         PrintAttributes fourthOldAttributes = thirdNewAttributes;
         PrintAttributes fourthNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.ISO_A4)
+                .setMediaSize(MediaSize.ISO_A0)
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(new Margins(200, 200, 200, 200))
                 .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
@@ -657,43 +666,34 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(1)
-                        .build();
-                // The content changes after every layout.
-                callback.onLayoutFinished(info, true);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                fd.close();
-                callback.onWriteFinished(pages);
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(1)
+                            .build();
+                    // The content changes after every layout.
+                    callback.onLayoutFinished(info, true);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                    fd.close();
+                    callback.onWriteFinished(pages);
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -732,7 +732,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -790,41 +790,32 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(1)
-                        .build();
-                // The content changes after every layout.
-                callback.onLayoutFinished(info, true);
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                fd.close();
-                callback.onWriteFinished(pages);
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(1)
+                            .build();
+                    // The content changes after every layout.
+                    callback.onLayoutFinished(info, true);
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                    fd.close();
+                    callback.onWriteFinished(pages);
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -860,7 +851,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -899,42 +890,33 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(3)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                PageRange[] pages = (PageRange[]) args[0];
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                fd.close();
-                callback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(3)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    PageRange[] pages = (PageRange[]) args[0];
+                    writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
+                    fd.close();
+                    callback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -973,7 +955,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -1027,30 +1009,21 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                CancellationSignal cancellation = (CancellationSignal) invocation.getArguments()[2];
-                final LayoutResultCallback callback = (LayoutResultCallback) invocation
-                        .getArguments()[3];
-                cancellation.setOnCancelListener(new OnCancelListener() {
-                    @Override
-                    public void onCancel() {
+                invocation -> {
+                    CancellationSignal cancellation = (CancellationSignal) invocation.getArguments()[2];
+                    final LayoutResultCallback callback = (LayoutResultCallback) invocation
+                            .getArguments()[3];
+                    cancellation.setOnCancelListener(() -> {
                         onCancelOperationCalled();
                         callback.onLayoutCancelled();
-                    }
+                    });
+                    onLayoutCalled();
+                    return null;
+                }, null, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
                 });
-                onLayoutCalled();
-                return null;
-            }
-        }, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
 
         // Start printing.
         print(adapter);
@@ -1081,7 +1054,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -1105,26 +1078,19 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                final ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                final CancellationSignal cancellation = (CancellationSignal) args[2];
-                final WriteResultCallback callback = (WriteResultCallback) args[3];
-                cancellation.setOnCancelListener(new OnCancelListener() {
-                    @Override
-                    public void onCancel() {
+                invocation -> {
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    final ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    final CancellationSignal cancellation = (CancellationSignal) args[2];
+                    final WriteResultCallback callback = (WriteResultCallback) args[3];
+                    cancellation.setOnCancelListener(() -> {
                         try {
                             fd.close();
                         } catch (IOException ioe) {
@@ -1132,20 +1098,15 @@
                         }
                         onCancelOperationCalled();
                         callback.onWriteCancelled();
-                    }
+                    });
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
                 });
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
 
         // Start printing.
         print(adapter);
@@ -1176,7 +1137,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -1205,23 +1166,17 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                callback.onLayoutFailed(null);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    callback.onLayoutFailed(null);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, null, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -1249,7 +1204,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -1275,36 +1230,27 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                fd.close();
-                callback.onWriteFailed(null);
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    fd.close();
+                    callback.onWriteFailed(null);
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -1332,7 +1278,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -1351,6 +1297,150 @@
         verifyNoMoreInteractions(adapter);
     }
 
+    public void testUnexpectedLayoutCancel() throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+        // Configure the print services.
+        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        final PrintAttributes[] printAttributes = new PrintAttributes[1];
+        final int[] numLayoutCalls = new int[1];
+
+        // Create a mock print adapter.
+        final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+
+                    // Returned cancelled for the second layout call which is unexpected
+                    if (numLayoutCalls[0] == 1) {
+                        callback.onLayoutCancelled();
+                    } else {
+                        callback.onLayoutFinished(
+                                (new PrintDocumentInfo.Builder(PRINT_JOB_NAME)).build(), false);
+                    }
+                    numLayoutCalls[0]++;
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(printAttributes[0], fd, 0, 1);
+                    fd.close();
+                    callback.onWriteFinished(pages);
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
+
+        // Start printing.
+        print(adapter);
+
+        // Wait for layout.
+        waitForLayoutAdapterCallbackCount(1);
+
+        // Select the second printer.
+        selectPrinter("Second printer");
+
+        // Wait for layout.
+        waitForLayoutAdapterCallbackCount(2);
+
+        // Retry layout (which should succeed) as the layout call will stop canceling after the
+        // second time
+        clickRetryButton();
+
+        // Click the print button.
+        clickPrintButton();
+
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
+        // Wait for the session to be destroyed to isolate tests.
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
+    public void testUnexpectedWriteCancel() throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+        // Configure the print services.
+        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        final PrintAttributes[] printAttributes = new PrintAttributes[1];
+        final int[] numWriteCalls = new int[1];
+
+        // Create a mock print adapter.
+        final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+
+                    callback.onLayoutFinished(
+                                (new PrintDocumentInfo.Builder(PRINT_JOB_NAME)).build(), true);
+
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+
+                    // Returned cancelled for the second write call which is unexpected
+                    if (numWriteCalls[0] == 1) {
+                        callback.onWriteCancelled();
+                    } else {
+                        PageRange[] pages = (PageRange[]) args[0];
+                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                        writeBlankPages(printAttributes[0], fd, 0, 1);
+                        fd.close();
+                        callback.onWriteFinished(pages);
+                    }
+                    numWriteCalls[0]++;
+
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
+
+        // Start printing.
+        print(adapter);
+
+        waitForWriteAdapterCallback(1);
+
+        // Select the second printer.
+        selectPrinter("Second printer");
+
+        // Wait for layout.
+        waitForWriteAdapterCallback(2);
+
+        // Retry write (which should succeed) as the write call will stop canceling after the
+        // second time
+        clickRetryButton();
+
+        // Click the print button.
+        clickPrintButton();
+
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
+        // Wait for the session to be destroyed to isolate tests.
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
     public void testRequestedPagesNotWritten() throws Exception {
         if (!supportsPrinting()) {
             return;
@@ -1363,40 +1453,31 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                      .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
-                      .build();
-                callback.onLayoutFinished(info, false);
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, Integer.MAX_VALUE, Integer.MAX_VALUE);
-                fd.close();
-                // Write wrong pages.
-                callback.onWriteFinished(new PageRange[] {
-                        new PageRange(Integer.MAX_VALUE,Integer.MAX_VALUE)});
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                          .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+                          .build();
+                    callback.onLayoutFinished(info, false);
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(printAttributes[0], fd, Integer.MAX_VALUE, Integer.MAX_VALUE);
+                    fd.close();
+                    // Write wrong pages.
+                    callback.onWriteFinished(new PageRange[] {
+                            new PageRange(Integer.MAX_VALUE,Integer.MAX_VALUE)});
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -1424,7 +1505,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -1453,22 +1534,16 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Break the contract and never call the callback.
-                // Mark layout called.
-                onLayoutCalled();
-                return null;
-            }
-        }, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    // Break the contract and never call the callback.
+                    // Mark layout called.
+                    onLayoutCalled();
+                    return null;
+                }, null, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -1496,7 +1571,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -1520,35 +1595,26 @@
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                fd.close();
-                // Break the contract and never call the callback.
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
-        });
+                invocation -> {
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+                            .build();
+                    callback.onLayoutFinished(info, false);
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    fd.close();
+                    // Break the contract and never call the callback.
+                    // Mark write was called.
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
 
         // Start printing.
         print(adapter);
@@ -1576,7 +1642,7 @@
         // there are other printers but none of them was used.
         PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
         PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
-                .setMediaSize(MediaSize.NA_LETTER)
+                .setMediaSize(getDefaultMediaSize())
                 .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
                 .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
                 .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
@@ -1595,6 +1661,174 @@
         verifyNoMoreInteractions(adapter);
     }
 
+    public void testLayoutCallbackCalledTwice() throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+        // Configure the print services.
+        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        // Create a mock print adapter.
+        final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+                invocation -> {
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(1)
+                            .build();
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation
+                            .getArguments()[3];
+
+                    // Break the contract and call the callback twice.
+                    callback.onLayoutFinished(info, true);
+                    callback.onLayoutFinished(info, true);
+
+                    // Mark layout called.
+                    onLayoutCalled();
+                    return null;
+                }, null, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
+
+        // Start printing.
+        print(adapter);
+
+        // Wait for layout.
+        waitForLayoutAdapterCallbackCount(1);
+
+        // Cancel printing.
+        getUiDevice().pressBack(); // wakes up the device.
+        getUiDevice().pressBack();
+
+        // Wait for a finish.
+        waitForAdapterFinishCallbackCalled();
+
+        // Wait for the session to be destroyed to isolate tests.
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+
+        // Verify the expected calls.
+        InOrder inOrder = inOrder(adapter);
+
+        // Start is always called first.
+        inOrder.verify(adapter).onStart();
+
+        // Start is always followed by a layout. The PDF printer is selected if
+        // there are other printers but none of them was used.
+        PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+        PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+                .setMediaSize(getDefaultMediaSize())
+                .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+                .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
+                .build();
+        verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+        PageRange[] firstPage = new PageRange[] {new PageRange(0, 0)};
+        inOrder.verify(adapter).onWrite(eq(firstPage), any(ParcelFileDescriptor.class),
+                any(CancellationSignal.class), any(WriteResultCallback.class));
+
+        // Finish is always called last.
+        inOrder.verify(adapter).onFinish();
+
+        // No other call are expected.
+        verifyNoMoreInteractions(adapter);
+    }
+
+    public void testWriteCallbackCalledTwice() throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+        // Configure the print services.
+        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        final PrintAttributes[] printAttributes = new PrintAttributes[1];
+
+        // Create a mock print adapter.
+        final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(1)
+                            .build();
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation
+                            .getArguments()[3];
+
+                    callback.onLayoutFinished(info, true);
+
+                    // Mark layout called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+
+                    // Write only one pages
+                    writeBlankPages(printAttributes[0], fd, 0, 0);
+                    fd.close();
+
+                    // Break the contract and call callback twice
+                    callback.onWriteFinished(pages);
+                    callback.onWriteFinished(pages);
+
+                    // Mark write called
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    // Mark finish was called.
+                    onFinishCalled();
+                    return null;
+                });
+
+        // Start printing.
+        print(adapter);
+
+        // Wait for layout.
+        waitForLayoutAdapterCallbackCount(1);
+
+        // Cancel printing.
+        getUiDevice().pressBack(); // wakes up the device.
+        getUiDevice().pressBack();
+
+        // Wait for a finish.
+        waitForAdapterFinishCallbackCalled();
+
+        // Wait for the session to be destroyed to isolate tests.
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+
+        // Verify the expected calls.
+        InOrder inOrder = inOrder(adapter);
+
+        // Start is always called first.
+        inOrder.verify(adapter).onStart();
+
+        // Start is always followed by a layout. The PDF printer is selected if
+        // there are other printers but none of them was used.
+        PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+        PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+                .setMediaSize(getDefaultMediaSize())
+                .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+                .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+                .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
+                .build();
+        verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+        PageRange[] firstPage = new PageRange[] {new PageRange(0, 0)};
+        inOrder.verify(adapter).onWrite(eq(firstPage), any(ParcelFileDescriptor.class),
+                any(CancellationSignal.class), any(WriteResultCallback.class));
+
+        // Finish is always called last.
+        inOrder.verify(adapter).onFinish();
+
+        // No other call are expected.
+        verifyNoMoreInteractions(adapter);
+    }
+
     /**
      * Pretend to have written two pages, but only actually write one page
      *
@@ -1611,44 +1845,35 @@
         final PrintAttributes[] printAttributes = new PrintAttributes[1];
 
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                        LayoutResultCallback callback = (LayoutResultCallback) invocation
-                                .getArguments()[3];
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation
+                            .getArguments()[3];
 
-                        // Lay out two pages
-                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                                .setPageCount(2)
-                                .build();
-                        callback.onLayoutFinished(info, true);
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        Object[] args = invocation.getArguments();
-                        PageRange[] pages = (PageRange[]) args[0];
-                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                        WriteResultCallback callback = (WriteResultCallback) args[3];
+                    // Lay out two pages
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(2)
+                            .build();
+                    callback.onLayoutFinished(info, true);
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
 
-                        // Write only one pages
-                        writeBlankPages(printAttributes[0], fd, 0, 0);
-                        fd.close();
+                    // Write only one pages
+                    writeBlankPages(printAttributes[0], fd, 0, 0);
+                    fd.close();
 
-                        // Break the contract and report that two pages were written
-                        callback.onWriteFinished(pages);
-                        onWriteCalled();
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        onFinishCalled();
-                        return null;
-                    }
+                    // Break the contract and report that two pages were written
+                    callback.onWriteFinished(pages);
+                    onWriteCalled();
+                    return null;
+                }, invocation -> {
+                    onFinishCalled();
+                    return null;
                 });
 
         print(adapter);
@@ -1668,52 +1893,65 @@
     /**
      * Executes a print process with a given print document info
      *
-     * @param info The print document info to declare on layout
+     * @param name The name of the document info
+     * @param contentType The content type of the document
+     * @param pageCount The number of pages in the document
      */
-    private void printDocumentInfoBaseTest(final PrintDocumentInfo info) throws Exception {
+    private void printDocumentBaseTest(String name, Integer contentType, Integer pageCount)
+            throws Throwable {
         if (!supportsPrinting()) {
             return;
         }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+
+        PrintDocumentInfo.Builder b = new PrintDocumentInfo.Builder(name);
+        if (contentType != null) {
+            b.setContentType(contentType);
+        }
+        if (pageCount != null) {
+            b.setPageCount(pageCount);
+        }
+        PrintDocumentInfo info = b.build();
+
+        PrintDocumentInfo queuedInfo[] = new PrintDocumentInfo[1];
+        ParcelFileDescriptor queuedData[] = new ParcelFileDescriptor[1];
+
+        PrinterDiscoverySessionCallbacks printerDiscoverySessionCallbacks =
+                createFirstMockDiscoverySessionCallbacks();
+        PrintServiceCallbacks printServiceCallbacks = createMockPrintServiceCallbacks(
+                invocation -> printerDiscoverySessionCallbacks,
+                invocation -> {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                    queuedInfo[0] = printJob.getDocument().getInfo();
+                    queuedData[0] = printJob.getDocument().getData();
+                    printJob.complete();
+                    return null;
+                }, null);
+
+        FirstPrintService.setCallbacks(printServiceCallbacks);
         SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
 
         final PrintAttributes[] printAttributes = new PrintAttributes[1];
 
         // Create a mock print adapter.
         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                        LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                        callback.onLayoutFinished(info, false);
-                        // Mark layout was called.
-                        onLayoutCalled();
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        Object[] args = invocation.getArguments();
-                        PageRange[] pages = (PageRange[]) args[0];
-                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                        WriteResultCallback callback = (WriteResultCallback) args[3];
-                        writeBlankPages(printAttributes[0], fd, 0, 1);
-                        fd.close();
-                        callback.onWriteFinished(pages);
-                        // Mark write was called.
-                        onWriteCalled();
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        // Mark finish was called.
-                        onFinishCalled();
-                        return null;
-                    }
-                });
+                invocation -> {
+                    printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation
+                            .getArguments()[3];
+                    callback.onLayoutFinished(info, false);
+                    // Mark layout was called.
+                    onLayoutCalled();
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
+                    writeBlankPages(printAttributes[0], fd, 0, 1);
+                    fd.close();
+                    callback.onWriteFinished(pages);
+                    return null;
+                }, invocation -> null);
 
         // Start printing.
         print(adapter);
@@ -1732,6 +1970,40 @@
 
         // Wait for the session to be destroyed to isolate tests.
         waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+
+        // Check that the document name was carried over 1:1
+        eventually(() -> assertEquals(name, queuedInfo[0].getName()));
+
+        // Content type is set to document by default, but is otherwise unrestricted
+        if (contentType != null) {
+            assertEquals(contentType, Integer.valueOf(queuedInfo[0].getContentType()));
+        } else {
+            assertEquals(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT, queuedInfo[0].getContentType());
+        }
+
+        // Page count is set to the real value if unknown, 0 or unset.
+        // Otherwise the set value is used
+        if (pageCount != null && pageCount != PrintDocumentInfo.PAGE_COUNT_UNKNOWN
+                && pageCount != 0) {
+            assertEquals(pageCount, Integer.valueOf(queuedInfo[0].getPageCount()));
+        } else {
+            assertEquals(2, queuedInfo[0].getPageCount());
+        }
+
+        // Verify data (== pdf file) size
+        assertTrue(queuedInfo[0].getDataSize() > 0);
+
+        long bytesRead = 0;
+        try (FileInputStream is = new FileInputStream(queuedData[0].getFileDescriptor())) {
+            while (true) {
+                int ret = is.read();
+                if (ret == -1) {
+                    break;
+                }
+                bytesRead++;
+            }
+        }
+        assertEquals(queuedInfo[0].getDataSize(), bytesRead);
     }
 
     /**
@@ -1739,8 +2011,8 @@
      *
      * @throws Exception If anything unexpected happens
      */
-    public void testDocumentInfoNothingSet() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME)).build());
+    public void testDocumentInfoNothingSet() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, null);
     }
 
     /**
@@ -1748,9 +2020,8 @@
      *
      * @throws Exception If anything unexpected happens
      */
-    public void testDocumentInfoUnknownPageCount() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN).build());
+    public void testDocumentInfoUnknownPageCount() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, PrintDocumentInfo.PAGE_COUNT_UNKNOWN);
     }
 
     /**
@@ -1758,9 +2029,8 @@
      *
      * @throws Exception If anything unexpected happens
      */
-    public void testDocumentInfoZeroPageCount() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setPageCount(0).build());
+    public void testDocumentInfoZeroPageCount() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, 0);
     }
 
     /**
@@ -1768,9 +2038,8 @@
      *
      * @throws Exception If anything unexpected happens
      */
-    public void testDocumentInfoOnePageCount() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setPageCount(1).build());
+    public void testDocumentInfoOnePageCount() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, 1);
     }
 
     /**
@@ -1778,9 +2047,8 @@
      *
      * @throws Exception If anything unexpected happens
      */
-    public void testDocumentInfoThreePageCount() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setPageCount(3).build());
+    public void testDocumentInfoThreePageCount() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, 3);
     }
 
     /**
@@ -1788,9 +2056,8 @@
      *
      * @throws Exception If anything unexpected happens
      */
-    public void testDocumentInfoContentTypePhoto() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO).build());
+    public void testDocumentInfoContentTypePhoto() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, PrintDocumentInfo.CONTENT_TYPE_PHOTO, null);
     }
 
     /**
@@ -1798,9 +2065,8 @@
      *
      * @throws Exception If anything unexpected happens
      */
-    public void testDocumentInfoContentTypeUnknown() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setContentType(PrintDocumentInfo.CONTENT_TYPE_UNKNOWN).build());
+    public void testDocumentInfoContentTypeUnknown() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, PrintDocumentInfo.CONTENT_TYPE_UNKNOWN, null);
     }
 
     /**
@@ -1808,104 +2074,99 @@
      *
      * @throws Exception If anything unexpected happens
      */
-    public void testDocumentInfoContentTypeNonDefined() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setContentType(-23).build());
+    public void testDocumentInfoContentTypeNonDefined() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, -23, null);
+    }
+
+    private PrinterDiscoverySessionCallbacks createFirstMockDiscoverySessionCallbacks() {
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            PrinterDiscoverySessionCallbacks mock = (PrinterDiscoverySessionCallbacks)
+                    invocation.getMock();
+
+            StubbablePrinterDiscoverySession session = mock.getSession();
+            PrintService service = session.getService();
+
+            if (session.getPrinters().isEmpty()) {
+                List<PrinterInfo> printers = new ArrayList<>();
+
+                // Add the first printer.
+                PrinterId firstPrinterId = service.generatePrinterId("first_printer");
+                PrinterCapabilitiesInfo firstCapabilities =
+                        new PrinterCapabilitiesInfo.Builder(firstPrinterId)
+                                .setMinMargins(new Margins(200, 200, 200, 200))
+                                .addMediaSize(MediaSize.ISO_A0, true)
+                                .addMediaSize(MediaSize.ISO_A5, false)
+                                .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                        PrintAttributes.COLOR_MODE_COLOR)
+                                .build();
+                PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
+                        "First printer", PrinterInfo.STATUS_IDLE)
+                        .setCapabilities(firstCapabilities)
+                        .build();
+                printers.add(firstPrinter);
+
+                // Add the second printer.
+                PrinterId secondPrinterId = service.generatePrinterId("second_printer");
+                PrinterCapabilitiesInfo secondCapabilities =
+                        new PrinterCapabilitiesInfo.Builder(secondPrinterId)
+                                .addMediaSize(MediaSize.ISO_A3, true)
+                                .addMediaSize(MediaSize.ISO_A0, false)
+                                .addResolution(new Resolution("200x200", "200x200", 200, 200), true)
+                                .addResolution(new Resolution("300x300", "300x300", 300, 300),
+                                        false)
+                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR
+                                                | PrintAttributes.COLOR_MODE_MONOCHROME,
+                                        PrintAttributes.COLOR_MODE_MONOCHROME
+                                )
+                                .setDuplexModes(PrintAttributes.DUPLEX_MODE_LONG_EDGE
+                                                | PrintAttributes.DUPLEX_MODE_SHORT_EDGE,
+                                        PrintAttributes.DUPLEX_MODE_LONG_EDGE
+                                )
+                                .build();
+                PrinterInfo secondPrinter = new PrinterInfo.Builder(secondPrinterId,
+                        "Second printer", PrinterInfo.STATUS_IDLE)
+                        .setCapabilities(secondCapabilities)
+                        .build();
+                printers.add(secondPrinter);
+
+                // Add the third printer.
+                PrinterId thirdPrinterId = service.generatePrinterId("third_printer");
+                PrinterCapabilitiesInfo thirdCapabilities =
+                        null;
+                try {
+                    thirdCapabilities = new PrinterCapabilitiesInfo.Builder(thirdPrinterId)
+                            .addMediaSize(getDefaultMediaSize(), true)
+                            .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+                            .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                    PrintAttributes.COLOR_MODE_COLOR)
+                            .build();
+                } catch (Exception e) {
+                    Log.e(LOG_TAG, "Cannot create third printer", e);
+                }
+                PrinterInfo thirdPrinter = new PrinterInfo.Builder(thirdPrinterId,
+                        "Third printer", PrinterInfo.STATUS_IDLE)
+                        .setCapabilities(thirdCapabilities)
+                        .build();
+                printers.add(thirdPrinter);
+
+                session.addPrinters(printers);
+            }
+            return null;
+        }, null, null, null, null, null, invocation -> {
+            // Take a note onDestroy was called.
+            onPrinterDiscoverySessionDestroyCalled();
+            return null;
+        });
     }
 
     private PrintServiceCallbacks createFirstMockPrintServiceCallbacks() {
         final PrinterDiscoverySessionCallbacks callbacks =
-                createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                PrinterDiscoverySessionCallbacks mock = (PrinterDiscoverySessionCallbacks)
-                        invocation.getMock();
-
-                StubbablePrinterDiscoverySession session = mock.getSession();
-                PrintService service = session.getService();
-
-                if (session.getPrinters().isEmpty()) {
-                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
-
-                    // Add the first printer.
-                    PrinterId firstPrinterId = service.generatePrinterId("first_printer");
-                    PrinterCapabilitiesInfo firstCapabilities =
-                            new PrinterCapabilitiesInfo.Builder(firstPrinterId)
-                        .setMinMargins(new Margins(200, 200, 200, 200))
-                        .addMediaSize(MediaSize.ISO_A4, true)
-                        .addMediaSize(MediaSize.ISO_A5, false)
-                        .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
-                        .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                PrintAttributes.COLOR_MODE_COLOR)
-                        .build();
-                    PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
-                            "First printer", PrinterInfo.STATUS_IDLE)
-                        .setCapabilities(firstCapabilities)
-                        .build();
-                    printers.add(firstPrinter);
-
-                    // Add the second printer.
-                    PrinterId secondPrinterId = service.generatePrinterId("second_printer");
-                    PrinterCapabilitiesInfo secondCapabilities =
-                            new PrinterCapabilitiesInfo.Builder(secondPrinterId)
-                        .addMediaSize(MediaSize.ISO_A3, true)
-                        .addMediaSize(MediaSize.ISO_A4, false)
-                        .addResolution(new Resolution("200x200", "200x200", 200, 200), true)
-                        .addResolution(new Resolution("300x300", "300x300", 300, 300), false)
-                        .setColorModes(PrintAttributes.COLOR_MODE_COLOR
-                                        | PrintAttributes.COLOR_MODE_MONOCHROME,
-                                PrintAttributes.COLOR_MODE_MONOCHROME
-                        )
-                        .setDuplexModes(PrintAttributes.DUPLEX_MODE_LONG_EDGE
-                                        | PrintAttributes.DUPLEX_MODE_SHORT_EDGE,
-                                PrintAttributes.DUPLEX_MODE_LONG_EDGE
-                        )
-                        .build();
-                    PrinterInfo secondPrinter = new PrinterInfo.Builder(secondPrinterId,
-                            "Second printer", PrinterInfo.STATUS_IDLE)
-                        .setCapabilities(secondCapabilities)
-                        .build();
-                    printers.add(secondPrinter);
-
-                    // Add the third printer.
-                    PrinterId thirdPrinterId = service.generatePrinterId("third_printer");
-                    PrinterCapabilitiesInfo thirdCapabilities =
-                            new PrinterCapabilitiesInfo.Builder(thirdPrinterId)
-                        .addMediaSize(MediaSize.NA_LETTER, true)
-                        .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
-                        .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                PrintAttributes.COLOR_MODE_COLOR)
-                        .build();
-                    PrinterInfo thirdPrinter = new PrinterInfo.Builder(thirdPrinterId,
-                            "Third printer", PrinterInfo.STATUS_IDLE)
-                        .setCapabilities(thirdCapabilities)
-                        .build();
-                    printers.add(thirdPrinter);
-
-                    session.addPrinters(printers);
-                }
-                return null;
-            }
-        }, null, null, null, null, null, new Answer<Void>() {
-                @Override
-                public Void answer(InvocationOnMock invocation) throws Throwable {
-                    // Take a note onDestroy was called.
-                    onPrinterDiscoverySessionDestroyCalled();
-                    return null;
-                }
-            });
-        return createMockPrintServiceCallbacks(new Answer<PrinterDiscoverySessionCallbacks>() {
-            @Override
-            public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                return callbacks;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                PrintJob printJob = (PrintJob) invocation.getArguments()[0];
-                printJob.complete();
-                return null;
-            }
+                createFirstMockDiscoverySessionCallbacks();
+        return createMockPrintServiceCallbacks(invocation -> callbacks, invocation -> {
+            PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+            printJob.complete();
+            return null;
         }, null);
     }
 
diff --git a/tests/tests/print/src/android/print/cts/PrintJobTest.java b/tests/tests/print/src/android/print/cts/PrintJobTest.java
index b0f3742e..e3d8eab 100644
--- a/tests/tests/print/src/android/print/cts/PrintJobTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintJobTest.java
@@ -37,19 +37,11 @@
 import android.print.cts.services.SecondPrintService;
 import android.print.cts.services.StubbablePrinterDiscoverySession;
 import android.printservice.PrintJob;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiSelector;
 import android.util.Log;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertFalse;
+import static android.print.cts.Utils.eventually;
 
 
 /**
@@ -71,53 +63,7 @@
     private final boolean testSuccess[] = new boolean[1];
 
     /** The printer discovery session used in this test */
-    private static StubbablePrinterDiscoverySession mDiscoverySession;
-
-    /**
-     * Create a mock {@link PrintDocumentAdapter} that provides one empty page.
-     *
-     * @return The mock adapter
-     */
-    private PrintDocumentAdapter createMockPrintDocumentAdapter() {
-        final PrintAttributes[] printAttributes = new PrintAttributes[1];
-
-        return createMockPrintDocumentAdapter(
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                        LayoutResultCallback callback = (LayoutResultCallback) invocation
-                                .getArguments()[3];
-
-                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                                .setPageCount(1)
-                                .build();
-
-                        callback.onLayoutFinished(info, false);
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        Object[] args = invocation.getArguments();
-                        PageRange[] pages = (PageRange[]) args[0];
-                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                        WriteResultCallback callback = (WriteResultCallback) args[3];
-
-                        writeBlankPages(printAttributes[0], fd, pages[0].getStart(),
-                                pages[0].getEnd());
-                        fd.close();
-                        callback.onWriteFinished(pages);
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        return null;
-                    }
-                });
-    }
+    private static StubbablePrinterDiscoverySession sDiscoverySession;
 
     /**
      * Create a mock {@link PrinterDiscoverySessionCallbacks} that discovers a simple test printer.
@@ -125,51 +71,40 @@
      * @return The mock session callbacks
      */
     private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
-        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                // Get the session.
-                mDiscoverySession = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
-                        .getSession();
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            // Get the session.
+            sDiscoverySession = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
+                    .getSession();
 
-                if (mDiscoverySession.getPrinters().isEmpty()) {
-                    PrinterId printerId =
-                            mDiscoverySession.getService().generatePrinterId(PRINTER_NAME);
-                    PrinterInfo.Builder printer = new PrinterInfo.Builder(
-                            mDiscoverySession.getService().generatePrinterId(PRINTER_NAME),
-                            PRINTER_NAME, PrinterInfo.STATUS_IDLE);
+            if (sDiscoverySession.getPrinters().isEmpty()) {
+                PrinterId printerId =
+                        sDiscoverySession.getService().generatePrinterId(PRINTER_NAME);
+                PrinterInfo.Builder printer = new PrinterInfo.Builder(
+                        sDiscoverySession.getService().generatePrinterId(PRINTER_NAME),
+                        PRINTER_NAME, PrinterInfo.STATUS_IDLE);
 
-                    printer.setCapabilities(new PrinterCapabilitiesInfo.Builder(printerId)
-                            .addMediaSize(MediaSize.ISO_A4, true)
-                            .addResolution(new Resolution("300x300", "300dpi", 300, 300), true)
-                            .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                    PrintAttributes.COLOR_MODE_COLOR)
-                            .setMinMargins(new Margins(0, 0, 0, 0)).build());
+                printer.setCapabilities(new PrinterCapabilitiesInfo.Builder(printerId)
+                        .addMediaSize(MediaSize.ISO_A4, true)
+                        .addResolution(new Resolution("300x300", "300dpi", 300, 300), true)
+                        .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                PrintAttributes.COLOR_MODE_COLOR)
+                        .setMinMargins(new Margins(0, 0, 0, 0)).build());
 
-                    ArrayList<PrinterInfo> printers = new ArrayList<>(1);
-                    printers.add(printer.build());
+                ArrayList<PrinterInfo> printers = new ArrayList<>(1);
+                printers.add(printer.build());
 
-                    mDiscoverySession.addPrinters(printers);
-                }
-                return null;
+                sDiscoverySession.addPrinters(printers);
             }
-        }, null, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                return null;
-            }
-        }, null, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Take a note onDestroy was called.
-                onPrinterDiscoverySessionDestroyCalled();
-                return null;
-            }
+            return null;
+        }, null, null, invocation -> null, null, null, invocation -> {
+            // Take a note onDestroy was called.
+            onPrinterDiscoverySessionDestroyCalled();
+            return null;
         });
     }
 
     private interface PrintJobTestFn {
-        void onPrintJobQueued(PrintJob printJob) throws Exception;
+        void onPrintJobQueued(PrintJob printJob) throws Throwable;
     }
 
     /**
@@ -183,57 +118,20 @@
             final PrinterDiscoverySessionCallbacks sessionCallbacks,
             final PrintJobTestFn printJobTest) {
         return createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return sessionCallbacks;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                invocation -> sessionCallbacks, invocation -> {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
 
-                        try {
-                            printJobTest.onPrintJobQueued(printJob);
-                            testSuccess[0] = true;
-                        } catch (Exception e) {
-                            Log.e(LOG_TAG, "Test function failed", e);
-                        }
-
-                        onPrintJobQueuedCalled();
-
-                        return null;
-                    }
-                }, null);
-    }
-
-    /**
-     * Make sure that a runnable eventually finishes without throwing a exception.
-     *
-     * @param r The runnable to run.
-     */
-    private static void eventually(Runnable r) {
-        final long TIMEOUT_MILLS = 5000;
-        long start = System.currentTimeMillis();
-
-        while (true) {
-            try {
-                r.run();
-                break;
-            } catch (Exception e) {
-                if (System.currentTimeMillis() - start < TIMEOUT_MILLS) {
-                    Log.e(LOG_TAG, "Ignoring exception as we know that the print spooler does " +
-                            "not guarantee to process commands in order", e);
                     try {
-                        Thread.sleep(100);
-                    } catch (InterruptedException e1) {
-                        Log.e(LOG_TAG, "Interrupted", e);
+                        printJobTest.onPrintJobQueued(printJob);
+                        testSuccess[0] = true;
+                    } catch (Throwable t) {
+                        throw new RuntimeException(t);
                     }
-                } else {
-                    throw e;
-                }
-            }
-        }
+
+                    onPrintJobQueuedCalled();
+
+                    return null;
+                }, null);
     }
 
     /**
@@ -265,7 +163,7 @@
         SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
 
         // Create a print adapter that respects the print contract.
-        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
         // Start printing.
         print(adapter);
@@ -355,7 +253,7 @@
         }
     }
 
-    private static void checkState(PrintJob job, int state) {
+    private static void checkState(PrintJob job, int state) throws Throwable {
         eventually(() -> assertEquals(state, job.getInfo().getState()));
         switch (state) {
             case PrintJobInfo.STATE_QUEUED:
@@ -416,43 +314,40 @@
 
                     Log.i(LOG_TAG, "Test " + state1 + " -> " + state2 + " -> " + state3);
 
-                    baseTest(new PrintJobTestFn() {
-                        @Override
-                        public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                            knownFailures[PrintJobInfo.STATE_QUEUED][state1] = true;
+                    baseTest(printJob -> {
+                        knownFailures[PrintJobInfo.STATE_QUEUED][state1] = true;
 
-                            boolean success = setState(printJob, state1);
-                            assertEquals(isStateTransitionAllowed(PrintJobInfo.STATE_QUEUED,
-                                    state1), success);
-                            if (!success) {
-                                return;
-                            }
-                            checkState(printJob, state1);
-
-                            knownFailures[PrintJobInfo.STATE_QUEUED][state1] = false;
-
-                            knownFailures[state1][state2] = true;
-
-                            success = setState(printJob, state2);
-                            assertEquals(isStateTransitionAllowed(state1, state2), success);
-                            if (!success) {
-                                return;
-                            }
-                            checkState(printJob, state2);
-
-                            knownFailures[state1][state2] = false;
-
-                            knownFailures[state2][state3] = true;
-
-                            success = setState(printJob, state3);
-                            assertEquals(isStateTransitionAllowed(state2, state3), success);
-                            if (!success) {
-                                return;
-                            }
-                            checkState(printJob, state3);
-
-                            knownFailures[state2][state3] = false;
+                        boolean success = setState(printJob, state1);
+                        assertEquals(isStateTransitionAllowed(PrintJobInfo.STATE_QUEUED,
+                                state1), success);
+                        if (!success) {
+                            return;
                         }
+                        checkState(printJob, state1);
+
+                        knownFailures[PrintJobInfo.STATE_QUEUED][state1] = false;
+
+                        knownFailures[state1][state2] = true;
+
+                        success = setState(printJob, state2);
+                        assertEquals(isStateTransitionAllowed(state1, state2), success);
+                        if (!success) {
+                            return;
+                        }
+                        checkState(printJob, state2);
+
+                        knownFailures[state1][state2] = false;
+
+                        knownFailures[state2][state3] = true;
+
+                        success = setState(printJob, state3);
+                        assertEquals(isStateTransitionAllowed(state2, state3), success);
+                        if (!success) {
+                            return;
+                        }
+                        checkState(printJob, state3);
+
+                        knownFailures[state2][state3] = false;
                     }, testCaseNum);
 
                     testCaseNum++;
@@ -462,70 +357,61 @@
     }
 
     public void testBlockWithReason() throws Exception {
-        baseTest(new PrintJobTestFn() {
-            @Override
-            public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                printJob.start();
-                checkState(printJob, PrintJobInfo.STATE_STARTED);
+        baseTest(printJob -> {
+            printJob.start();
+            checkState(printJob, PrintJobInfo.STATE_STARTED);
 
-                printJob.setStatus(R.string.testStr1);
-                eventually(() -> assertEquals(getActivity().getString(R.string.testStr1),
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            printJob.setStatus(R.string.testStr1);
+            eventually(() -> assertEquals(getActivity().getString(R.string.testStr1),
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                boolean success = printJob.block("test reason");
-                assertTrue(success);
-                checkState(printJob, PrintJobInfo.STATE_BLOCKED);
-                eventually(() -> assertEquals("test reason",
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            boolean success = printJob.block("test reason");
+            assertTrue(success);
+            checkState(printJob, PrintJobInfo.STATE_BLOCKED);
+            eventually(() -> assertEquals("test reason",
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                success = printJob.block("another reason");
-                assertFalse(success);
-                checkState(printJob, PrintJobInfo.STATE_BLOCKED);
-                eventually(() -> assertEquals("test reason",
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            success = printJob.block("another reason");
+            assertFalse(success);
+            checkState(printJob, PrintJobInfo.STATE_BLOCKED);
+            eventually(() -> assertEquals("test reason",
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                printJob.setStatus(R.string.testStr2);
-                eventually(() -> assertEquals(getActivity().getString(R.string.testStr2),
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
-            }
+            printJob.setStatus(R.string.testStr2);
+            eventually(() -> assertEquals(getActivity().getString(R.string.testStr2),
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
         }, 0);
     }
 
     public void testFailWithReason() throws Exception {
-        baseTest(new PrintJobTestFn() {
-            @Override
-            public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                printJob.start();
-                checkState(printJob, PrintJobInfo.STATE_STARTED);
+        baseTest(printJob -> {
+            printJob.start();
+            checkState(printJob, PrintJobInfo.STATE_STARTED);
 
-                boolean success = printJob.fail("test reason");
-                assertTrue(success);
-                checkState(printJob, PrintJobInfo.STATE_FAILED);
-                eventually(() -> assertEquals("test reason",
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            boolean success = printJob.fail("test reason");
+            assertTrue(success);
+            checkState(printJob, PrintJobInfo.STATE_FAILED);
+            eventually(() -> assertEquals("test reason",
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                success = printJob.fail("another reason");
-                assertFalse(success);
-                checkState(printJob, PrintJobInfo.STATE_FAILED);
-                eventually(() -> assertEquals("test reason",
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
-            }
+            success = printJob.fail("another reason");
+            assertFalse(success);
+            checkState(printJob, PrintJobInfo.STATE_FAILED);
+            eventually(() -> assertEquals("test reason",
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
         }, 0);
     }
 
     public void testTag() throws Exception {
-        baseTest(new PrintJobTestFn() {
-            @Override
-            public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                // Default value should be null
-                assertNull(printJob.getTag());
+        baseTest(printJob -> {
+            // Default value should be null
+            assertNull(printJob.getTag());
 
-                printJob.setTag("testTag");
-                eventually(() -> assertEquals("testTag", printJob.getTag()));
+            printJob.setTag("testTag");
+            eventually(() -> assertEquals("testTag", printJob.getTag()));
 
-                printJob.setTag(null);
-                eventually(() -> assertNull(printJob.getTag()));
-            }
+            printJob.setTag(null);
+            eventually(() -> assertNull(printJob.getTag()));
         }, 0);
     }
 
@@ -542,54 +428,47 @@
 
         // Create the service callbacks for the first print service.
         PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
-                sessionCallbacks, new PrintJobTestFn() {
-                    @Override
-                    public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                        assertTrue(printJob.hasAdvancedOption(VALID_STRING_KEY));
-                        assertEquals(STRING_VALUE, printJob.getAdvancedStringOption(VALID_STRING_KEY));
+                sessionCallbacks, printJob -> {
+                    assertTrue(printJob.hasAdvancedOption(VALID_STRING_KEY));
+                    assertEquals(STRING_VALUE, printJob.getAdvancedStringOption(VALID_STRING_KEY));
 
-                        assertFalse(printJob.hasAdvancedOption(INVALID_STRING_KEY));
-                        assertNull(printJob.getAdvancedStringOption(INVALID_STRING_KEY));
+                    assertFalse(printJob.hasAdvancedOption(INVALID_STRING_KEY));
+                    assertNull(printJob.getAdvancedStringOption(INVALID_STRING_KEY));
 
-                        assertTrue(printJob.hasAdvancedOption(VALID_INT_KEY));
-                        assertEquals(INT_VALUE, printJob.getAdvancedIntOption(VALID_INT_KEY));
+                    assertTrue(printJob.hasAdvancedOption(VALID_INT_KEY));
+                    assertEquals(INT_VALUE, printJob.getAdvancedIntOption(VALID_INT_KEY));
 
-                        assertTrue(printJob.hasAdvancedOption(VALID_NULL_KEY));
-                        assertNull(printJob.getAdvancedStringOption(VALID_NULL_KEY));
+                    assertTrue(printJob.hasAdvancedOption(VALID_NULL_KEY));
+                    assertNull(printJob.getAdvancedStringOption(VALID_NULL_KEY));
 
-                        assertFalse(printJob.hasAdvancedOption(INVALID_INT_KEY));
-                        assertEquals(0, printJob.getAdvancedIntOption(INVALID_INT_KEY));
+                    assertFalse(printJob.hasAdvancedOption(INVALID_INT_KEY));
+                    assertEquals(0, printJob.getAdvancedIntOption(INVALID_INT_KEY));
 
-                        assertNull(printJob.getAdvancedStringOption(VALID_INT_KEY));
-                        assertEquals(0, printJob.getAdvancedIntOption(VALID_STRING_KEY));
-                    }
+                    assertNull(printJob.getAdvancedStringOption(VALID_INT_KEY));
+                    assertEquals(0, printJob.getAdvancedIntOption(VALID_STRING_KEY));
                 });
 
         CustomPrintOptionsActivity.setCallBack(
-                new CustomPrintOptionsActivity.CustomPrintOptionsCallback() {
-                    @Override
-                    public PrintJobInfo executeCustomPrintOptionsActivity(
-                            PrintJobInfo printJob, PrinterInfo printer) {
-                        PrintJobInfo.Builder printJobBuilder = new PrintJobInfo.Builder(printJob);
+                (printJob, printer) -> {
+                    PrintJobInfo.Builder printJobBuilder = new PrintJobInfo.Builder(printJob);
 
-                        try {
-                            printJobBuilder.putAdvancedOption(null, STRING_VALUE);
-                            throw new RuntimeException("Should not be able to use a null key");
-                        } catch (NullPointerException e) {
-                            // expected
-                        }
-
-                        // Second put overrides the first
-                        printJobBuilder.putAdvancedOption(VALID_STRING_KEY, "something");
-                        printJobBuilder.putAdvancedOption(VALID_STRING_KEY, STRING_VALUE);
-
-                        printJobBuilder.putAdvancedOption(VALID_INT_KEY, "something");
-                        printJobBuilder.putAdvancedOption(VALID_INT_KEY, INT_VALUE);
-
-                        printJobBuilder.putAdvancedOption(VALID_NULL_KEY, null);
-
-                        return printJobBuilder.build();
+                    try {
+                        printJobBuilder.putAdvancedOption(null, STRING_VALUE);
+                        throw new RuntimeException("Should not be able to use a null key");
+                    } catch (NullPointerException e) {
+                        // expected
                     }
+
+                    // Second put overrides the first
+                    printJobBuilder.putAdvancedOption(VALID_STRING_KEY, "something");
+                    printJobBuilder.putAdvancedOption(VALID_STRING_KEY, STRING_VALUE);
+
+                    printJobBuilder.putAdvancedOption(VALID_INT_KEY, "something");
+                    printJobBuilder.putAdvancedOption(VALID_INT_KEY, INT_VALUE);
+
+                    printJobBuilder.putAdvancedOption(VALID_NULL_KEY, null);
+
+                    return printJobBuilder.build();
                 });
 
         // Configure the print services.
@@ -599,7 +478,7 @@
         SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
 
         // Create a print adapter that respects the print contract.
-        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
         // Start printing.
         print(adapter);
@@ -622,57 +501,51 @@
     }
 
     public void testOther() throws Exception {
-        baseTest(new PrintJobTestFn() {
-            @Override
-            public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                assertNotNull(printJob.getDocument());
-                assertNotNull(printJob.getId());
-            }
+        baseTest(printJob -> {
+            assertNotNull(printJob.getDocument());
+            assertNotNull(printJob.getId());
         }, 0);
     }
 
     public void testSetStatus() throws Exception {
-        baseTest(new PrintJobTestFn() {
-            @Override
-            public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                printJob.start();
+        baseTest(printJob -> {
+            printJob.start();
 
-                printJob.setStatus(R.string.testStr1);
-                eventually(() -> assertEquals(getActivity().getString(R.string.testStr1),
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            printJob.setStatus(R.string.testStr1);
+            eventually(() -> assertEquals(getActivity().getString(R.string.testStr1),
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                printJob.setStatus("testStr3");
-                eventually(() -> assertEquals("testStr3",
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            printJob.setStatus("testStr3");
+            eventually(() -> assertEquals("testStr3",
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                printJob.setStatus(R.string.testStr2);
-                eventually(() -> assertEquals(getActivity().getString(R.string.testStr2),
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            printJob.setStatus(R.string.testStr2);
+            eventually(() -> assertEquals(getActivity().getString(R.string.testStr2),
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                printJob.setStatus(null);
-                eventually(() -> assertNull(
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            printJob.setStatus(null);
+            eventually(() -> assertNull(
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                printJob.block("testStr4");
-                eventually(() -> assertEquals("testStr4",
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            printJob.block("testStr4");
+            eventually(() -> assertEquals("testStr4",
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                printJob.setStatus(R.string.testStr2);
-                eventually(() -> assertEquals(getActivity().getString(R.string.testStr2),
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            printJob.setStatus(R.string.testStr2);
+            eventually(() -> assertEquals(getActivity().getString(R.string.testStr2),
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                printJob.setStatus(0);
-                eventually(() -> assertNull(
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            printJob.setStatus(0);
+            eventually(() -> assertNull(
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                printJob.setStatus("testStr3");
-                eventually(() -> assertEquals("testStr3",
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
+            printJob.setStatus("testStr3");
+            eventually(() -> assertEquals("testStr3",
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
 
-                printJob.setStatus(-1);
-                eventually(() -> assertNull(
-                        printJob.getInfo().getStatus(getActivity().getPackageManager())));
-            }
+            printJob.setStatus(-1);
+            eventually(() -> assertNull(
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
         }, 0);
     }
 }
diff --git a/tests/tests/print/src/android/print/cts/PrintServicesTest.java b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
index ccb1f07..ddfcd05 100644
--- a/tests/tests/print/src/android/print/cts/PrintServicesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -28,19 +29,12 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
-import android.print.PageRange;
 import android.print.PrintAttributes;
 import android.print.PrintAttributes.Margins;
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Resolution;
 import android.print.PrintDocumentAdapter;
-import android.print.PrintDocumentAdapter.LayoutResultCallback;
-import android.print.PrintDocumentAdapter.WriteResultCallback;
-import android.print.PrintDocumentInfo;
+import android.print.PrintManager;
 import android.print.PrinterCapabilitiesInfo;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
@@ -48,6 +42,7 @@
 import android.print.cts.services.PrintServiceCallbacks;
 import android.print.cts.services.PrinterDiscoverySessionCallbacks;
 import android.print.cts.services.SecondPrintService;
+import android.print.cts.services.StubbablePrintService;
 import android.print.cts.services.StubbablePrinterDiscoverySession;
 import android.printservice.CustomPrinterIconCallback;
 import android.printservice.PrintJob;
@@ -55,288 +50,162 @@
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiSelector;
 
-import junit.framework.AssertionFailedError;
-
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
-import java.util.concurrent.TimeoutException;
+
+import static android.print.cts.Utils.assertException;
+import static android.print.cts.Utils.eventually;
+import static android.print.cts.Utils.getPrintJob;
+import static android.print.cts.Utils.runOnMainThread;
 
 /**
  * Test the interface from a print service to the print manager
  */
 public class PrintServicesTest extends BasePrintTest {
     private static final String PRINTER_NAME = "Test printer";
-    private static final int NUM_PAGES = 2;
 
     /** The print job processed in the test */
-    private static PrintJob mPrintJob;
-
-    /** The current progress of #mPrintJob once read from the system */
-    private static float mPrintProgress;
+    private static PrintJob sPrintJob;
 
     /** Printer under test */
-    private static PrinterInfo mPrinter;
-
-    /** The printer discovery session used in this test */
-    private static StubbablePrinterDiscoverySession mDiscoverySession;
-
-    /** The current status of #mPrintJob once read from the system */
-    private static CharSequence mPrintStatus;
+    private static PrinterInfo sPrinter;
 
     /** The custom printer icon to use */
     private Icon mIcon;
 
     /**
-     * Create a mock {@link PrintDocumentAdapter} that provides {@link #NUM_PAGES} empty pages.
-     *
-     * @return The mock adapter
-     */
-    private PrintDocumentAdapter createMockPrintDocumentAdapter() {
-        final PrintAttributes[] printAttributes = new PrintAttributes[1];
-
-        return createMockPrintDocumentAdapter(
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                        LayoutResultCallback callback = (LayoutResultCallback) invocation
-                                .getArguments()[3];
-
-                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                                .setPageCount(NUM_PAGES)
-                                .build();
-
-                        callback.onLayoutFinished(info, false);
-
-                        // Mark layout was called.
-                        onLayoutCalled();
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        Object[] args = invocation.getArguments();
-                        PageRange[] pages = (PageRange[]) args[0];
-                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                        WriteResultCallback callback = (WriteResultCallback) args[3];
-
-                        writeBlankPages(printAttributes[0], fd, pages[0].getStart(),
-                                pages[0].getEnd());
-                        fd.close();
-                        callback.onWriteFinished(pages);
-
-                        // Mark write was called.
-                        onWriteCalled();
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        // Mark finish was called.
-                        onFinishCalled();
-                        return null;
-                    }
-                });
-    }
-
-    /**
      * Create a mock {@link PrinterDiscoverySessionCallbacks} that discovers a single printer with
      * minimal capabilities.
      *
      * @return The mock session callbacks
      */
-    private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
-        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                // Get the session.
-                mDiscoverySession = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
-                        .getSession();
+    private PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
+            String printerName) {
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            // Get the session.
+            StubbablePrinterDiscoverySession session =
+                    ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
 
-                if (mDiscoverySession.getPrinters().isEmpty()) {
-                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+            if (session.getPrinters().isEmpty()) {
+                List<PrinterInfo> printers = new ArrayList<>();
 
-                    // Add the printer.
-                    PrinterId printerId = mDiscoverySession.getService()
-                            .generatePrinterId(PRINTER_NAME);
+                // Add the printer.
+                PrinterId printerId = session.getService()
+                        .generatePrinterId(printerName);
 
-                    PrinterCapabilitiesInfo capabilities = new PrinterCapabilitiesInfo.Builder(
-                            printerId)
-                                    .setMinMargins(new Margins(200, 200, 200, 200))
-                                    .addMediaSize(MediaSize.ISO_A4, true)
-                                    .addResolution(new Resolution("300x300", "300x300", 300, 300),
-                                            true)
-                                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                            PrintAttributes.COLOR_MODE_COLOR)
-                                    .build();
+                PrinterCapabilitiesInfo capabilities = new PrinterCapabilitiesInfo.Builder(
+                        printerId)
+                        .setMinMargins(new Margins(200, 200, 200, 200))
+                        .addMediaSize(MediaSize.ISO_A4, true)
+                        .addResolution(new Resolution("300x300", "300x300", 300, 300),
+                                true)
+                        .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                PrintAttributes.COLOR_MODE_COLOR)
+                        .build();
 
-                    Intent infoIntent = new Intent(getActivity(), Activity.class);
-                    PendingIntent infoPendingIntent = PendingIntent.getActivity(getActivity(), 0,
-                            infoIntent, PendingIntent.FLAG_IMMUTABLE);
+                Intent infoIntent = new Intent(getActivity(), Activity.class);
+                PendingIntent infoPendingIntent = PendingIntent.getActivity(getActivity(), 0,
+                        infoIntent, PendingIntent.FLAG_IMMUTABLE);
 
-                    mPrinter = new PrinterInfo.Builder(printerId, PRINTER_NAME,
-                            PrinterInfo.STATUS_IDLE)
-                                    .setCapabilities(capabilities)
-                                    .setDescription("Minimal capabilities")
-                                    .setInfoIntent(infoPendingIntent)
-                                    .build();
-                    printers.add(mPrinter);
+                sPrinter = new PrinterInfo.Builder(printerId, printerName,
+                        PrinterInfo.STATUS_IDLE)
+                        .setCapabilities(capabilities)
+                        .setDescription("Minimal capabilities")
+                        .setInfoIntent(infoPendingIntent)
+                        .build();
+                printers.add(sPrinter);
 
-                    mDiscoverySession.addPrinters(printers);
-                }
-                return null;
+                session.addPrinters(printers);
             }
-        }, null, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                CustomPrinterIconCallback callback = (CustomPrinterIconCallback) invocation
-                        .getArguments()[2];
 
-                if (mIcon != null) {
-                    callback.onCustomPrinterIconLoaded(mIcon);
-                }
-                return null;
+            onPrinterDiscoverySessionCreateCalled();
+
+            return null;
+        }, null, null, invocation -> null, invocation -> {
+            CustomPrinterIconCallback callback = (CustomPrinterIconCallback) invocation
+                    .getArguments()[2];
+
+            if (mIcon != null) {
+                callback.onCustomPrinterIconLoaded(mIcon);
             }
-        }, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Take a note onDestroy was called.
-                onPrinterDiscoverySessionDestroyCalled();
-                return null;
-            }
+            return null;
+        }, null, invocation -> {
+            // Take a note onDestroy was called.
+            onPrinterDiscoverySessionDestroyCalled();
+            return null;
         });
     }
 
     /**
-     * Get the current progress of #mPrintJob
+     * Get the current progress of #sPrintJob
      *
      * @return The current progress
+     *
      * @throws InterruptedException If the thread was interrupted while setting the progress
+     * @throws Throwable            If anything is unexpected.
      */
-    private float getProgress() throws InterruptedException {
-        final PrintServicesTest synchronizer = PrintServicesTest.this;
+    private float getProgress() throws Throwable {
+        float[] printProgress = new float[1];
+        runOnMainThread(() -> printProgress[0] = sPrintJob.getInfo().getProgress());
 
-        synchronized (synchronizer) {
-            Runnable getter = new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (synchronizer) {
-                        mPrintProgress = mPrintJob.getInfo().getProgress();
-
-                        synchronizer.notify();
-                    }
-                }
-            };
-
-            (new Handler(Looper.getMainLooper())).post(getter);
-
-            synchronizer.wait();
-        }
-
-        return mPrintProgress;
+        return printProgress[0];
     }
 
     /**
-     * Get the current status of #mPrintJob
+     * Get the current status of #sPrintJob
      *
      * @return The current status
+     *
      * @throws InterruptedException If the thread was interrupted while getting the status
+     * @throws Throwable            If anything is unexpected.
      */
-    private CharSequence getStatus() throws InterruptedException {
-        final PrintServicesTest synchronizer = PrintServicesTest.this;
+    private CharSequence getStatus() throws Throwable {
+        CharSequence[] printStatus = new CharSequence[1];
+        runOnMainThread(() -> printStatus[0] = sPrintJob.getInfo().getStatus(getActivity()
+                .getPackageManager()));
 
-        synchronized (synchronizer) {
-            Runnable getter = new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (synchronizer) {
-                        mPrintStatus = mPrintJob.getInfo()
-                                .getStatus(getActivity().getPackageManager());
-
-                        synchronizer.notify();
-                    }
-                }
-            };
-
-            (new Handler(Looper.getMainLooper())).post(getter);
-
-            synchronizer.wait();
-        }
-
-        return mPrintStatus;
+        return printStatus[0];
     }
 
     /**
      * Check if a print progress is correct.
      *
      * @param desiredProgress The expected @{link PrintProgresses}
-     * @throws Exception If anything goes wrong or this takes more than 5 seconds
+     *
+     * @throws Throwable If anything goes wrong or this takes more than 5 seconds
      */
-    private void checkNotification(float desiredProgress,
-            CharSequence desiredStatus) throws Exception {
-        final long TIMEOUT = 5000;
-        final Date start = new Date();
-
-        while ((new Date()).getTime() - start.getTime() < TIMEOUT) {
-            if (desiredProgress == getProgress()
-                    && desiredStatus.toString().equals(getStatus().toString())) {
-                return;
-            }
-
-            Thread.sleep(200);
-        }
-
-        throw new TimeoutException("Progress or status not updated in " + TIMEOUT + " ms");
+    private void checkNotification(float desiredProgress, CharSequence desiredStatus)
+            throws Throwable {
+        eventually(() -> assertEquals(desiredProgress, getProgress()));
+        eventually(() -> assertEquals(desiredStatus.toString(), getStatus().toString()));
     }
 
     /**
-     * Set a new progress and status for #mPrintJob
+     * Set a new progress and status for #sPrintJob
      *
      * @param progress The new progress to set
-     * @param status The new status to set
+     * @param status   The new status to set
+     *
      * @throws InterruptedException If the thread was interrupted while setting
+     * @throws Throwable            If anything is unexpected.
      */
     private void setProgressAndStatus(final float progress, final CharSequence status)
-            throws InterruptedException {
-        final PrintServicesTest synchronizer = PrintServicesTest.this;
-
-        synchronized (synchronizer) {
-            Runnable completer = new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (synchronizer) {
-                        mPrintJob.setProgress(progress);
-                        mPrintJob.setStatus(status);
-
-                        synchronizer.notify();
-                    }
-                }
-            };
-
-            (new Handler(Looper.getMainLooper())).post(completer);
-
-            synchronizer.wait();
-        }
+            throws Throwable {
+        runOnMainThread(() -> {
+            sPrintJob.setProgress(progress);
+            sPrintJob.setStatus(status);
+        });
     }
 
     /**
      * Progress print job and check the print job state.
      *
      * @param progress How much to progress
-     * @param status The status to set
-     * @throws Exception If anything goes wrong.
+     * @param status   The status to set
+     *
+     * @throws Throwable If anything goes wrong.
      */
-    private void progress(float progress, CharSequence status) throws Exception {
+    private void progress(float progress, CharSequence status) throws Throwable {
         setProgressAndStatus(progress, status);
 
         // Check that progress of job is correct
@@ -348,43 +217,39 @@
      *
      * @param sessionCallbacks The callbacks of the sessopm
      */
-    private PrintServiceCallbacks createFirstMockPrinterServiceCallbacks(
+    private PrintServiceCallbacks createMockPrinterServiceCallbacks(
             final PrinterDiscoverySessionCallbacks sessionCallbacks) {
         return createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return sessionCallbacks;
-                    }
-                },
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        mPrintJob = (PrintJob) invocation.getArguments()[0];
-                        mPrintJob.start();
-                        onPrintJobQueuedCalled();
+                invocation -> sessionCallbacks,
+                invocation -> {
+                    sPrintJob = (PrintJob) invocation.getArguments()[0];
+                    sPrintJob.start();
+                    onPrintJobQueuedCalled();
 
-                        return null;
-                    }
-                }, null);
+                    return null;
+                }, invocation -> {
+                    sPrintJob = (PrintJob) invocation.getArguments()[0];
+                    sPrintJob.cancel();
+
+                    return null;
+                });
     }
 
     /**
      * Test that the progress and status is propagated correctly.
      *
-     * @throws Exception If anything is unexpected.
+     * @throws Throwable If anything is unexpected.
      */
-    public void testProgress()
-            throws Exception {
+    public void testProgress() throws Throwable {
         if (!supportsPrinting()) {
             return;
         }
         // Create the session callbacks that we will be checking.
         PrinterDiscoverySessionCallbacks sessionCallbacks
-                = createFirstMockPrinterDiscoverySessionCallbacks();
+                = createMockPrinterDiscoverySessionCallbacks(PRINTER_NAME);
 
         // Create the service callbacks for the first print service.
-        PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
+        PrintServiceCallbacks serviceCallbacks = createMockPrinterServiceCallbacks(
                 sessionCallbacks);
 
         // Configure the print services.
@@ -394,7 +259,7 @@
         SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
 
         // Create a print adapter that respects the print contract.
-        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
         // Start printing.
         print(adapter);
@@ -411,7 +276,7 @@
         // Answer the dialog for the print service cloud warning
         answerPrintServicesWarning(true);
 
-        // Wait until the print job is queued and #mPrintJob is set
+        // Wait until the print job is queued and #sPrintJob is set
         waitForServiceOnPrintJobQueuedCallbackCalled(1);
 
         // Progress print job and check for appropriate notifications
@@ -420,16 +285,7 @@
         progress(1, "printed 100");
 
         // Call complete from the main thread
-        Handler handler = new Handler(Looper.getMainLooper());
-
-        Runnable completer = new Runnable() {
-            @Override
-            public void run() {
-                mPrintJob.complete();
-            }
-        };
-
-        handler.post(completer);
+        runOnMainThread(sPrintJob::complete);
 
         // Wait for all print jobs to be handled after which the session destroyed.
         waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
@@ -439,6 +295,7 @@
      * Render a {@link Drawable} into a {@link Bitmap}.
      *
      * @param d the drawable to be rendered
+     *
      * @return the rendered bitmap
      */
     private static Bitmap renderDrawable(Drawable d) {
@@ -455,34 +312,22 @@
     /**
      * Update the printer
      *
+     * @param sessionCallbacks The callbacks for the service the printer belongs to
      * @param printer the new printer to use
+     *
      * @throws InterruptedException If we were interrupted while the printer was updated.
+     * @throws Throwable            If anything is unexpected.
      */
-    private void updatePrinter(final PrinterInfo printer)
-            throws InterruptedException {
-        final PrintServicesTest synchronizer = PrintServicesTest.this;
-
-        synchronized (synchronizer) {
-            Runnable updated = new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (synchronizer) {
-                        ArrayList<PrinterInfo> printers = new ArrayList<>(1);
-                        printers.add(printer);
-                        mDiscoverySession.addPrinters(printers);
-
-                        synchronizer.notifyAll();
-                    }
-                }
-            };
-
-            (new Handler(Looper.getMainLooper())).post(updated);
-
-            synchronizer.wait();
-        }
+    private void updatePrinter(PrinterDiscoverySessionCallbacks sessionCallbacks,
+            final PrinterInfo printer) throws Throwable {
+        runOnMainThread(() -> {
+            ArrayList<PrinterInfo> printers = new ArrayList<>(1);
+            printers.add(printer);
+            sessionCallbacks.getSession().addPrinters(printers);
+        });
 
         // Update local copy of printer
-        mPrinter = printer;
+        sPrinter = printer;
     }
 
     /**
@@ -490,46 +335,29 @@
      * we try up to 5 seconds.
      *
      * @param bitmap The bitmap to match
+     *
+     * @throws Throwable If anything is unexpected.
      */
-    private void assertThatIconIs(Bitmap bitmap) {
-        final long TIMEOUT = 5000;
-
-        final long startMillis = SystemClock.uptimeMillis();
-        while (true) {
-            try {
-                if (bitmap.sameAs(renderDrawable(mPrinter.loadIcon(getActivity())))) {
-                    return;
-                }
-                final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
-                final long waitMillis = TIMEOUT - elapsedMillis;
-                if (waitMillis <= 0) {
-                    throw new AssertionFailedError("Icon does not match bitmap");
-                }
-
-                // We do not get notified about the icon update, hence wait and try again.
-                Thread.sleep(1000);
-            } catch (InterruptedException ie) {
-               /* ignore */
-            }
-        }
+    private void assertThatIconIs(Bitmap bitmap) throws Throwable {
+        eventually(
+                () -> assertTrue(bitmap.sameAs(renderDrawable(sPrinter.loadIcon(getActivity())))));
     }
 
     /**
      * Test that the icon get be updated.
      *
-     * @throws Exception If anything is unexpected.
+     * @throws Throwable If anything is unexpected.
      */
-    public void testUpdateIcon()
-            throws Exception {
+    public void testUpdateIcon() throws Throwable {
         if (!supportsPrinting()) {
             return;
         }
         // Create the session callbacks that we will be checking.
         final PrinterDiscoverySessionCallbacks sessionCallbacks
-                = createFirstMockPrinterDiscoverySessionCallbacks();
+                = createMockPrinterDiscoverySessionCallbacks(PRINTER_NAME);
 
         // Create the service callbacks for the first print service.
-        PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
+        PrintServiceCallbacks serviceCallbacks = createMockPrinterServiceCallbacks(
                 sessionCallbacks);
 
         // Configure the print services.
@@ -539,7 +367,7 @@
         SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
 
         // Create a print adapter that respects the print contract.
-        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
         // Start printing.
         print(adapter);
@@ -560,18 +388,154 @@
         assertThatIconIs(renderDrawable(printServiceIcon));
 
         // Update icon to resource
-        updatePrinter((new PrinterInfo.Builder(mPrinter)).setIconResourceId(R.drawable.red_printer)
+        updatePrinter(sessionCallbacks,
+                (new PrinterInfo.Builder(sPrinter)).setIconResourceId(R.drawable.red_printer)
                 .build());
 
         assertThatIconIs(renderDrawable(getActivity().getDrawable(R.drawable.red_printer)));
 
         // Update icon to bitmap
         Bitmap bm = BitmapFactory.decodeResource(getActivity().getResources(),
-                R.raw.yellow_printer);
+                R.raw.yellow);
         // Icon will be picked up from the discovery session once setHasCustomPrinterIcon is set
         mIcon = Icon.createWithBitmap(bm);
-        updatePrinter((new PrinterInfo.Builder(mPrinter)).setHasCustomPrinterIcon(true).build());
+        updatePrinter(sessionCallbacks,
+                (new PrinterInfo.Builder(sPrinter)).setHasCustomPrinterIcon(true).build());
 
         assertThatIconIs(renderDrawable(mIcon.loadDrawable(getActivity())));
     }
+
+    /**
+     * Test that we cannot call attachBaseContext
+     *
+     * @throws Throwable If anything is unexpected.
+     */
+    public void testCannotUseAttachBaseContext() throws Throwable {
+        if (!supportsPrinting()) {
+            return;
+        }
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks sessionCallbacks
+                = createMockPrinterDiscoverySessionCallbacks(PRINTER_NAME);
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks serviceCallbacks = createMockPrinterServiceCallbacks(
+                sessionCallbacks);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(serviceCallbacks);
+
+        // Create a print adapter that respects the print contract.
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+
+        // We don't use the second service, but we have to still configure it
+        SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+        // Start printing to set serviceCallbacks.getService()
+        print(adapter);
+        eventually(() -> assertNotNull(serviceCallbacks.getService()));
+
+        // attachBaseContext should always throw an exception no matter what input value
+        assertException(() -> serviceCallbacks.getService().callAttachBaseContext(null),
+                IllegalStateException.class);
+        assertException(() -> serviceCallbacks.getService().callAttachBaseContext(getActivity()),
+                IllegalStateException.class);
+    }
+
+    /**
+     * Test that the active print jobs can be read
+     *
+     * @throws Throwable If anything is unexpected.
+     */
+    public void testGetActivePrintJobs() throws Throwable {
+        if (!supportsPrinting()) {
+            return;
+        }
+
+        PrintManager pm = (PrintManager) getActivity().getSystemService(Context.PRINT_SERVICE);
+
+        // Configure first print service
+        PrinterDiscoverySessionCallbacks sessionCallbacks1
+                = createMockPrinterDiscoverySessionCallbacks("Printer1");
+        PrintServiceCallbacks serviceCallbacks1 = createMockPrinterServiceCallbacks(
+                sessionCallbacks1);
+        FirstPrintService.setCallbacks(serviceCallbacks1);
+
+        // Configure second print service
+        PrinterDiscoverySessionCallbacks sessionCallbacks2
+                = createMockPrinterDiscoverySessionCallbacks("Printer2");
+        PrintServiceCallbacks serviceCallbacks2 = createMockPrinterServiceCallbacks(
+                sessionCallbacks2);
+        SecondPrintService.setCallbacks(serviceCallbacks2);
+
+        // Create a print adapter that respects the print contract.
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+
+        runOnMainThread(() -> pm.print("job1", adapter, null));
+
+        // Init services
+        waitForPrinterDiscoverySessionCreateCallbackCalled();
+        StubbablePrintService firstService = serviceCallbacks1.getService();
+
+        waitForWriteAdapterCallback(1);
+        selectPrinter("Printer1");
+
+        // Job is not yet confirmed, hence it is not yet "active"
+        runOnMainThread(() -> assertEquals(0, firstService.callGetActivePrintJobs().size()));
+
+        clickPrintButton();
+        answerPrintServicesWarning(true);
+        onPrintJobQueuedCalled();
+
+        eventually(() -> runOnMainThread(
+                () -> assertEquals(1, firstService.callGetActivePrintJobs().size())));
+
+        // Add another print job to first service
+        resetCounters();
+        runOnMainThread(() -> pm.print("job2", adapter, null));
+        waitForWriteAdapterCallback(1);
+        clickPrintButton();
+        onPrintJobQueuedCalled();
+
+        eventually(() -> runOnMainThread(
+                () -> assertEquals(2, firstService.callGetActivePrintJobs().size())));
+
+        // Create print job in second service
+        resetCounters();
+        runOnMainThread(() -> pm.print("job3", adapter, null));
+
+        waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+        StubbablePrintService secondService = serviceCallbacks2.getService();
+        runOnMainThread(() -> assertEquals(0, secondService.callGetActivePrintJobs().size()));
+
+        waitForWriteAdapterCallback(1);
+        selectPrinter("Printer2");
+        clickPrintButton();
+        answerPrintServicesWarning(true);
+        onPrintJobQueuedCalled();
+
+        eventually(() -> runOnMainThread(
+                () -> assertEquals(1, secondService.callGetActivePrintJobs().size())));
+        runOnMainThread(() -> assertEquals(2, firstService.callGetActivePrintJobs().size()));
+
+        // Block last print job. Blocked jobs are still considered active
+        runOnMainThread(() -> sPrintJob.block(null));
+        eventually(() -> runOnMainThread(() -> assertTrue(sPrintJob.isBlocked())));
+        runOnMainThread(() -> assertEquals(1, secondService.callGetActivePrintJobs().size()));
+
+        // Fail last print job. Failed job are not active
+        runOnMainThread(() -> sPrintJob.fail(null));
+        eventually(() -> runOnMainThread(() -> assertTrue(sPrintJob.isFailed())));
+        runOnMainThread(() -> assertEquals(0, secondService.callGetActivePrintJobs().size()));
+
+        // Cancel job. Canceled jobs are not active
+        runOnMainThread(() -> assertEquals(2, firstService.callGetActivePrintJobs().size()));
+        android.print.PrintJob job2 = getPrintJob(pm, "job2");
+        runOnMainThread(job2::cancel);
+        eventually(() -> runOnMainThread(() -> assertTrue(job2.isCancelled())));
+        runOnMainThread(() -> assertEquals(1, firstService.callGetActivePrintJobs().size()));
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
 }
diff --git a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
index 8e3f984..ec8676a 100644
--- a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
@@ -37,8 +37,6 @@
 import android.util.Log;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiSelector;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -46,6 +44,8 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 
+import static android.print.cts.Utils.assertException;
+
 /**
  * This test verifies changes to the printer capabilities are applied correctly.
  */
@@ -133,14 +133,10 @@
      */
     private void changeCapabilities(final StubbablePrinterDiscoverySession session,
             final PrinterId printerId, final MediaSize mediaSize, final boolean isAvailable) {
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                session.addPrinters(generatePrinters(printerId, mediaSize, isAvailable ?
+        getInstrumentation().runOnMainSync(
+                () -> session.addPrinters(generatePrinters(printerId, mediaSize, isAvailable ?
                         PrinterInfo.STATUS_IDLE :
-                        PrinterInfo.STATUS_UNAVAILABLE));
-            }
-        });
+                        PrinterInfo.STATUS_UNAVAILABLE)));
     }
 
     /**
@@ -149,7 +145,8 @@
      * @throws Exception If anything was unexpected.
      */
     private void waitForPrinterUnavailable() throws Exception {
-        final String PRINTER_UNAVAILABLE_MSG = "This printer isn't available right now.";
+        final String PRINTER_UNAVAILABLE_MSG =
+                getPrintSpoolerString("print_error_printer_unavailable");
 
         UiObject message = getUiDevice().findObject(new UiSelector().resourceId(
                 "com.android.printspooler:id/message"));
@@ -186,47 +183,40 @@
         final PrintAttributes[] writeAttributes = new PrintAttributes[1];
 
         PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        LayoutResultCallback callback = (LayoutResultCallback) invocation
-                                .getArguments()[3];
-                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                                .setPageCount(1)
-                                .build();
+                invocation -> {
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation
+                            .getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(1)
+                            .build();
 
-                        synchronized (PrinterCapabilitiesTest.this) {
-                            layoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                    synchronized (PrinterCapabilitiesTest.this) {
+                        layoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
 
-                            PrinterCapabilitiesTest.this.notify();
-                        }
-
-                        callback.onLayoutFinished(info, true);
-                        return null;
+                        PrinterCapabilitiesTest.this.notify();
                     }
-                },
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        Object[] args = invocation.getArguments();
-                        PageRange[] pages = (PageRange[]) args[0];
-                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                        WriteResultCallback callback = (WriteResultCallback) args[3];
 
-                        writeBlankPages(layoutAttributes[0], fd, pages[0].getStart(),
-                                pages[0].getEnd());
-                        fd.close();
+                    callback.onLayoutFinished(info, true);
+                    return null;
+                }, invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
 
-                        synchronized (PrinterCapabilitiesTest.this) {
-                            writeAttributes[0] = layoutAttributes[0];
+                    writeBlankPages(layoutAttributes[0], fd, pages[0].getStart(),
+                            pages[0].getEnd());
+                    fd.close();
 
-                            PrinterCapabilitiesTest.this.notify();
-                        }
+                    synchronized (PrinterCapabilitiesTest.this) {
+                        writeAttributes[0] = layoutAttributes[0];
 
-                        callback.onWriteFinished(pages);
-                        return null;
+                        PrinterCapabilitiesTest.this.notify();
                     }
+
+                    callback.onWriteFinished(pages);
+                    return null;
                 }, null);
 
         // Start printing.
@@ -275,34 +265,23 @@
 
         // Create the session[0] callbacks that we will be checking.
         final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
-                createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        session[0] = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
-                                .getSession();
+                createMockPrinterDiscoverySessionCallbacks(invocation -> {
+                    session[0] = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
+                            .getSession();
 
-                        printerId[0] = session[0].getService().generatePrinterId(PRINTER_NAME);
+                    printerId[0] = session[0].getService().generatePrinterId(PRINTER_NAME);
 
-                        session[0].addPrinters(generatePrinters(printerId[0], MediaSize.NA_LETTER,
-                                PrinterInfo.STATUS_IDLE));
-                        return null;
-                    }
-                }, null, null, null, null, null, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        onPrinterDiscoverySessionDestroyCalled();
-                        return null;
-                    }
+                    session[0].addPrinters(generatePrinters(printerId[0], MediaSize.NA_LETTER,
+                            PrinterInfo.STATUS_IDLE));
+                    return null;
+                }, null, null, null, null, null, invocation -> {
+                    onPrinterDiscoverySessionDestroyCalled();
+                    return null;
                 });
 
         // Create the service callbacks for the first print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return firstSessionCallbacks;
-                    }
-                }, null, null);
+                invocation -> firstSessionCallbacks, null, null);
 
         // Configure the print services.
         FirstPrintService.setCallbacks(firstServiceCallbacks);
@@ -335,27 +314,6 @@
     }
 
     /**
-     * Run a runnable and expect and exception of a certain type.
-     *
-     * @param r The runnable to run
-     * @param expectedClass The expected exception type
-     */
-    private void assertException(Runnable r, Class<? extends RuntimeException> expectedClass) {
-        try {
-            r.run();
-        } catch (Exception e) {
-            if (e.getClass().isAssignableFrom(expectedClass)) {
-                return;
-            } else {
-                throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
-                        + e.getClass().getName());
-            }
-        }
-
-        throw new AssertionError("No exception thrown");
-    }
-
-    /**
      * That that you cannot create illegal PrinterCapabilityInfos.
      *
      * @throws Exception If anything is unexpected
@@ -366,105 +324,94 @@
         }
 
         final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
-                createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        StubbablePrinterDiscoverySession session =
-                                ((PrinterDiscoverySessionCallbacks)
-                                        invocation.getMock()).getSession();
+                createMockPrinterDiscoverySessionCallbacks(invocation -> {
+                    StubbablePrinterDiscoverySession session =
+                            ((PrinterDiscoverySessionCallbacks)
+                                    invocation.getMock()).getSession();
 
-                        PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
+                    PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
 
-                        // printerId need to be set
-                        assertException(() -> new PrinterCapabilitiesInfo.Builder(null),
-                                IllegalArgumentException.class);
+                    // printerId need to be set
+                    assertException(() -> new PrinterCapabilitiesInfo.Builder(null),
+                            IllegalArgumentException.class);
 
-                        // All capability fields (beside duplex) need to be initialized:
-                        // Test no color
-                        assertException(() ->
-                                        (new PrinterCapabilitiesInfo.Builder(printerId))
-                                                .setMinMargins(DEFAULT_MARGINS)
-                                                .addMediaSize(MediaSize.ISO_A4, true)
-                                                .addResolution(RESOLUTION_300, true).build(),
-                                IllegalStateException.class);
-                        // Test bad colors
-                        assertException(() ->
-                                        (new PrinterCapabilitiesInfo.Builder(printerId))
-                                                .setColorModes(0xffff,
-                                                        PrintAttributes.COLOR_MODE_MONOCHROME),
-                                IllegalArgumentException.class);
-                        // Test bad duplex mode
-                        assertException(() ->
-                                        (new PrinterCapabilitiesInfo.Builder(printerId))
-                                                .setDuplexModes(0xffff,
-                                                        PrintAttributes.DUPLEX_MODE_NONE),
-                                IllegalArgumentException.class);
-                        // Test no mediasize
-                        assertException(() ->
-                                        (new PrinterCapabilitiesInfo.Builder(printerId))
-                                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                                        PrintAttributes.COLOR_MODE_COLOR)
-                                                .setMinMargins(DEFAULT_MARGINS)
-                                                .addResolution(RESOLUTION_300, true).build(),
-                                IllegalStateException.class);
-                        // Test no default mediasize
-                        assertException(() ->
-                                        (new PrinterCapabilitiesInfo.Builder(printerId))
-                                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                                        PrintAttributes.COLOR_MODE_COLOR)
-                                                .setMinMargins(DEFAULT_MARGINS)
-                                                .addMediaSize(MediaSize.ISO_A4, false)
-                                                .addResolution(RESOLUTION_300, true).build(),
-                                IllegalStateException.class);
-                        // Test two default mediasizes
-                        assertException(() ->
-                                        (new PrinterCapabilitiesInfo.Builder(printerId))
-                                                .addMediaSize(MediaSize.ISO_A4, true)
-                                                .addMediaSize(MediaSize.ISO_A5, true),
-                                IllegalArgumentException.class);
-                        // Test no resolution
-                        assertException(() ->
-                                        (new PrinterCapabilitiesInfo.Builder(printerId))
-                                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                                        PrintAttributes.COLOR_MODE_COLOR)
-                                                .setMinMargins(DEFAULT_MARGINS)
-                                                .addMediaSize(MediaSize.ISO_A4, true).build(),
-                                IllegalStateException.class);
-                        // Test no default resolution
-                        assertException(() ->
-                                        (new PrinterCapabilitiesInfo.Builder(printerId))
-                                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                                        PrintAttributes.COLOR_MODE_COLOR)
-                                                .setMinMargins(DEFAULT_MARGINS)
-                                                .addMediaSize(MediaSize.ISO_A4, true)
-                                                .addResolution(RESOLUTION_300, false).build(),
-                                IllegalStateException.class);
-                        // Test two default resolutions
-                        assertException(() ->
-                                        (new PrinterCapabilitiesInfo.Builder(printerId))
-                                                .addResolution(RESOLUTION_300, true)
-                                                .addResolution(RESOLUTION_600, true),
-                                IllegalArgumentException.class);
+                    // All capability fields (beside duplex) need to be initialized:
+                    // Test no color
+                    assertException(() ->
+                                    (new PrinterCapabilitiesInfo.Builder(printerId))
+                                            .setMinMargins(DEFAULT_MARGINS)
+                                            .addMediaSize(MediaSize.ISO_A4, true)
+                                            .addResolution(RESOLUTION_300, true).build(),
+                            IllegalStateException.class);
+                    // Test bad colors
+                    assertException(() ->
+                                    (new PrinterCapabilitiesInfo.Builder(printerId))
+                                            .setColorModes(0xffff,
+                                                    PrintAttributes.COLOR_MODE_MONOCHROME),
+                            IllegalArgumentException.class);
+                    // Test bad duplex mode
+                    assertException(() ->
+                                    (new PrinterCapabilitiesInfo.Builder(printerId))
+                                            .setDuplexModes(0xffff,
+                                                    PrintAttributes.DUPLEX_MODE_NONE),
+                            IllegalArgumentException.class);
+                    // Test no mediasize
+                    assertException(() ->
+                                    (new PrinterCapabilitiesInfo.Builder(printerId))
+                                            .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                                    PrintAttributes.COLOR_MODE_COLOR)
+                                            .setMinMargins(DEFAULT_MARGINS)
+                                            .addResolution(RESOLUTION_300, true).build(),
+                            IllegalStateException.class);
+                    // Test no default mediasize
+                    assertException(() ->
+                                    (new PrinterCapabilitiesInfo.Builder(printerId))
+                                            .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                                    PrintAttributes.COLOR_MODE_COLOR)
+                                            .setMinMargins(DEFAULT_MARGINS)
+                                            .addMediaSize(MediaSize.ISO_A4, false)
+                                            .addResolution(RESOLUTION_300, true).build(),
+                            IllegalStateException.class);
+                    // Test two default mediasizes
+                    assertException(() ->
+                                    (new PrinterCapabilitiesInfo.Builder(printerId))
+                                            .addMediaSize(MediaSize.ISO_A4, true)
+                                            .addMediaSize(MediaSize.ISO_A5, true),
+                            IllegalArgumentException.class);
+                    // Test no resolution
+                    assertException(() ->
+                                    (new PrinterCapabilitiesInfo.Builder(printerId))
+                                            .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                                    PrintAttributes.COLOR_MODE_COLOR)
+                                            .setMinMargins(DEFAULT_MARGINS)
+                                            .addMediaSize(MediaSize.ISO_A4, true).build(),
+                            IllegalStateException.class);
+                    // Test no default resolution
+                    assertException(() ->
+                                    (new PrinterCapabilitiesInfo.Builder(printerId))
+                                            .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                                    PrintAttributes.COLOR_MODE_COLOR)
+                                            .setMinMargins(DEFAULT_MARGINS)
+                                            .addMediaSize(MediaSize.ISO_A4, true)
+                                            .addResolution(RESOLUTION_300, false).build(),
+                            IllegalStateException.class);
+                    // Test two default resolutions
+                    assertException(() ->
+                                    (new PrinterCapabilitiesInfo.Builder(printerId))
+                                            .addResolution(RESOLUTION_300, true)
+                                            .addResolution(RESOLUTION_600, true),
+                            IllegalArgumentException.class);
 
-                        onPrinterDiscoverySessionCreateCalled();
-                        return null;
-                    }
-                }, null, null, null, null, null, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        onPrinterDiscoverySessionDestroyCalled();
-                        return null;
-                    }
+                    onPrinterDiscoverySessionCreateCalled();
+                    return null;
+                }, null, null, null, null, null, invocation -> {
+                    onPrinterDiscoverySessionDestroyCalled();
+                    return null;
                 });
 
         // Create the service callbacks for the first print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return firstSessionCallbacks;
-                    }
-                }, null, null);
+                invocation -> firstSessionCallbacks, null, null);
 
         // Configure the print services.
         FirstPrintService.setCallbacks(firstServiceCallbacks);
@@ -493,91 +440,114 @@
         }
 
         final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
-                createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        StubbablePrinterDiscoverySession session =
-                                ((PrinterDiscoverySessionCallbacks)
-                                        invocation.getMock()).getSession();
+                createMockPrinterDiscoverySessionCallbacks(invocation -> {
+                    StubbablePrinterDiscoverySession session =
+                            ((PrinterDiscoverySessionCallbacks)
+                                    invocation.getMock()).getSession();
 
-                        MediaSize[] mediaSizes = {MediaSize.ISO_A0, MediaSize.ISO_A0,
-                                MediaSize.ISO_A1};
-                        Resolution[] resolutions = {RESOLUTION_300, RESOLUTION_300,
-                                RESOLUTION_600};
-                        int[] colorModes = {PrintAttributes.COLOR_MODE_MONOCHROME,
-                                PrintAttributes.COLOR_MODE_COLOR};
-                        int[] duplexModes = {PrintAttributes.DUPLEX_MODE_NONE,
-                                PrintAttributes.DUPLEX_MODE_LONG_EDGE,
-                                PrintAttributes.DUPLEX_MODE_SHORT_EDGE};
+                    MediaSize[] mediaSizes = {MediaSize.ISO_A0, MediaSize.ISO_A0,
+                            MediaSize.ISO_A1};
+                    Resolution[] resolutions = {RESOLUTION_300, RESOLUTION_300,
+                            RESOLUTION_600};
+                    int[] colorModes = {PrintAttributes.COLOR_MODE_MONOCHROME,
+                            PrintAttributes.COLOR_MODE_COLOR};
+                    int[] duplexModes = {PrintAttributes.DUPLEX_MODE_NONE,
+                            PrintAttributes.DUPLEX_MODE_LONG_EDGE,
+                            PrintAttributes.DUPLEX_MODE_SHORT_EDGE};
 
-                        ArrayList<PrinterInfo> printers = new ArrayList<>();
-                        for (int mediaSizeIndex = 1; mediaSizeIndex < mediaSizes.length;
-                             mediaSizeIndex++) {
-                            for (int resolutionIndex = 1; resolutionIndex < mediaSizes.length;
-                                 resolutionIndex++) {
-                                for (int colorIndex = 1; colorIndex < colorModes.length;
-                                     colorIndex++) {
-                                    for (int duplexIndex = 1; duplexIndex < duplexModes.length;
-                                         duplexIndex++) {
-                                        PrinterId printerId = session.getService()
-                                                .generatePrinterId(Integer.valueOf(printers.size())
-                                                        .toString());
+                    ArrayList<PrinterInfo> printers = new ArrayList<>();
+                    for (int mediaSizeIndex = 1; mediaSizeIndex < mediaSizes.length;
+                         mediaSizeIndex++) {
+                        for (int resolutionIndex = 1; resolutionIndex < mediaSizes.length;
+                             resolutionIndex++) {
+                            for (int colorIndex = 1; colorIndex < colorModes.length;
+                                 colorIndex++) {
+                                for (int duplexIndex = 1; duplexIndex < duplexModes.length;
+                                     duplexIndex++) {
+                                    PrinterId printerId = session.getService()
+                                            .generatePrinterId(Integer.valueOf(printers.size())
+                                                    .toString());
 
-                                        PrinterCapabilitiesInfo.Builder b =
-                                                new PrinterCapabilitiesInfo.Builder(printerId);
+                                    // Setup capabilities
+                                    PrinterCapabilitiesInfo.Builder b =
+                                            new PrinterCapabilitiesInfo.Builder(printerId);
 
-                                        for (int i = 0; i < mediaSizeIndex; i++) {
-                                            b.addMediaSize(mediaSizes[i], i == mediaSizeIndex - 1);
-                                        }
-
-                                        for (int i = 0; i < resolutionIndex; i++) {
-                                            b.addResolution(resolutions[i],
-                                                    i == resolutionIndex - 1);
-                                        }
-
-                                        int allColors = 0;
-                                        for (int i = 0; i < colorIndex; i++) {
-                                            allColors |= colorModes[i];
-                                        }
-                                        b.setColorModes(allColors, colorModes[colorIndex - 1]);
-
-                                        int allDuplexModes = 0;
-                                        for (int i = 0; i < duplexIndex; i++) {
-                                            allDuplexModes |= duplexModes[i];
-                                        }
-                                        b.setDuplexModes(allDuplexModes,
-                                                duplexModes[duplexIndex - 1]);
-
-                                        printers.add((new PrinterInfo.Builder(printerId,
-                                                Integer.valueOf(printers.size()).toString(),
-                                                PrinterInfo.STATUS_IDLE)).setCapabilities(b.build())
-                                                .build());
+                                    for (int i = 0; i < mediaSizeIndex; i++) {
+                                        b.addMediaSize(mediaSizes[i], i == mediaSizeIndex - 1);
                                     }
+
+                                    for (int i = 0; i < resolutionIndex; i++) {
+                                        b.addResolution(resolutions[i],
+                                                i == resolutionIndex - 1);
+                                    }
+
+                                    int allColors = 0;
+                                    for (int i = 0; i < colorIndex; i++) {
+                                        allColors |= colorModes[i];
+                                    }
+                                    b.setColorModes(allColors, colorModes[colorIndex - 1]);
+
+                                    int allDuplexModes = 0;
+                                    for (int i = 0; i < duplexIndex; i++) {
+                                        allDuplexModes |= duplexModes[i];
+                                    }
+                                    b.setDuplexModes(allDuplexModes,
+                                            duplexModes[duplexIndex - 1]);
+
+                                    b.setMinMargins(DEFAULT_MARGINS);
+
+                                    // Create printer
+                                    PrinterInfo printer = (new PrinterInfo.Builder(printerId,
+                                            Integer.valueOf(printers.size()).toString(),
+                                            PrinterInfo.STATUS_IDLE)).setCapabilities(b.build())
+                                            .build();
+
+                                    // Verify capabilities
+                                    PrinterCapabilitiesInfo cap = printer.getCapabilities();
+
+                                    assertEquals(mediaSizeIndex, cap.getMediaSizes().size());
+                                    assertEquals(mediaSizes[mediaSizeIndex - 1],
+                                            cap.getDefaults().getMediaSize());
+                                    for (int i = 0; i < mediaSizeIndex; i++) {
+                                        assertTrue(cap.getMediaSizes().contains(mediaSizes[i]));
+                                    }
+
+                                    assertEquals(resolutionIndex, cap.getResolutions().size());
+                                    assertEquals(resolutions[resolutionIndex - 1],
+                                            cap.getDefaults().getResolution());
+                                    for (int i = 0; i < resolutionIndex; i++) {
+                                        assertTrue(cap.getResolutions().contains(resolutions[i]));
+                                    }
+
+                                    assertEquals(allColors, cap.getColorModes());
+                                    assertEquals(colorModes[colorIndex - 1],
+                                            cap.getDefaults().getColorMode());
+
+                                    assertEquals(allDuplexModes, cap.getDuplexModes());
+                                    assertEquals(duplexModes[duplexIndex - 1],
+                                            cap.getDefaults().getDuplexMode());
+
+                                    assertEquals(DEFAULT_MARGINS, cap.getMinMargins());
+
+                                    // Add printer
+                                    printers.add(printer);
                                 }
                             }
                         }
-
-                        session.addPrinters(printers);
-
-                        onPrinterDiscoverySessionCreateCalled();
-                        return null;
                     }
-                }, null, null, null, null, null, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        onPrinterDiscoverySessionDestroyCalled();
-                        return null;
-                    }
+
+                    session.addPrinters(printers);
+
+                    onPrinterDiscoverySessionCreateCalled();
+                    return null;
+                }, null, null, null, null, null, invocation -> {
+                    onPrinterDiscoverySessionDestroyCalled();
+                    return null;
                 });
 
         // Create the service callbacks for the first print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return firstSessionCallbacks;
-                    }
-                }, null, null);
+                invocation -> firstSessionCallbacks, null, null);
 
         // Configure the print services.
         FirstPrintService.setCallbacks(firstServiceCallbacks);
@@ -608,42 +578,31 @@
         }
 
         final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
-                createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        StubbablePrinterDiscoverySession session =
-                                ((PrinterDiscoverySessionCallbacks)
-                                        invocation.getMock()).getSession();
+                createMockPrinterDiscoverySessionCallbacks(invocation -> {
+                    StubbablePrinterDiscoverySession session =
+                            ((PrinterDiscoverySessionCallbacks)
+                                    invocation.getMock()).getSession();
 
-                        PrinterId printerId = session.getService()
-                                .generatePrinterId(PRINTER_NAME);
+                    PrinterId printerId = session.getService()
+                            .generatePrinterId(PRINTER_NAME);
 
-                        ArrayList<PrinterInfo> printers = new ArrayList<>();
-                        printers.add((new PrinterInfo.Builder(printerId, PRINTER_NAME,
-                                PrinterInfo.STATUS_IDLE))
-                                .setCapabilities(capBuilder.apply(printerId)).build());
+                    ArrayList<PrinterInfo> printers = new ArrayList<>();
+                    printers.add((new PrinterInfo.Builder(printerId, PRINTER_NAME,
+                            PrinterInfo.STATUS_IDLE))
+                            .setCapabilities(capBuilder.apply(printerId)).build());
 
-                        session.addPrinters(printers);
+                    session.addPrinters(printers);
 
-                        onPrinterDiscoverySessionCreateCalled();
-                        return null;
-                    }
-                }, null, null, null, null, null, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        onPrinterDiscoverySessionDestroyCalled();
-                        return null;
-                    }
+                    onPrinterDiscoverySessionCreateCalled();
+                    return null;
+                }, null, null, null, null, null, invocation -> {
+                    onPrinterDiscoverySessionDestroyCalled();
+                    return null;
                 });
 
         // Create the service callbacks for the first print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return firstSessionCallbacks;
-                    }
-                }, null, null);
+                invocation -> firstSessionCallbacks, null, null);
 
         // Configure the print services.
         FirstPrintService.setCallbacks(firstServiceCallbacks);
@@ -652,35 +611,29 @@
         final PrintAttributes[] layoutAttributes = new PrintAttributes[1];
 
         PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        LayoutResultCallback callback = (LayoutResultCallback) invocation
-                                .getArguments()[3];
-                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                                .setPageCount(1)
-                                .build();
-                        layoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                invocation -> {
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation
+                            .getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setPageCount(1)
+                            .build();
+                    layoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
 
-                        callback.onLayoutFinished(info, true);
-                        return null;
-                    }
+                    callback.onLayoutFinished(info, true);
+                    return null;
                 },
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        Object[] args = invocation.getArguments();
-                        PageRange[] pages = (PageRange[]) args[0];
-                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                        WriteResultCallback callback = (WriteResultCallback) args[3];
+                invocation -> {
+                    Object[] args = invocation.getArguments();
+                    PageRange[] pages = (PageRange[]) args[0];
+                    ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                    WriteResultCallback callback = (WriteResultCallback) args[3];
 
-                        writeBlankPages(layoutAttributes[0], fd, pages[0].getStart(),
-                                pages[0].getEnd());
-                        fd.close();
+                    writeBlankPages(layoutAttributes[0], fd, pages[0].getStart(),
+                            pages[0].getEnd());
+                    fd.close();
 
-                        callback.onWriteFinished(pages);
-                        return null;
-                    }
+                    callback.onWriteFinished(pages);
+                    return null;
                 }, null);
 
         // Start printing.
diff --git a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
index defbee3..3830770 100644
--- a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
@@ -16,18 +16,15 @@
 
 package android.print.cts;
 
+import static android.print.cts.Utils.eventually;
+import static android.print.cts.Utils.runOnMainThread;
 import static org.mockito.Mockito.inOrder;
 
-import android.os.ParcelFileDescriptor;
-import android.print.PageRange;
 import android.print.PrintAttributes;
 import android.print.PrintAttributes.Margins;
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Resolution;
 import android.print.PrintDocumentAdapter;
-import android.print.PrintDocumentAdapter.LayoutResultCallback;
-import android.print.PrintDocumentAdapter.WriteResultCallback;
-import android.print.PrintDocumentInfo;
 import android.print.PrinterCapabilitiesInfo;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
@@ -41,8 +38,6 @@
 
 import org.mockito.InOrder;
 import org.mockito.exceptions.verification.VerificationInOrderFailure;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -59,7 +54,9 @@
     private static final String FIRST_PRINTER_LOCAL_ID= "first_printer";
     private static final String SECOND_PRINTER_LOCAL_ID = "second_printer";
 
-    public void testNormalLifecycle() throws Exception {
+    private static StubbablePrinterDiscoverySession sSession;
+
+    public void testNormalLifecycle() throws Throwable {
         if (!supportsPrinting()) {
             return;
         }
@@ -69,28 +66,20 @@
 
         // Create the service callbacks for the first print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                @Override
-                public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return firstSessionCallbacks;
-                    }
-                },
-                new Answer<Void>() {
-                @Override
-                public Void answer(InvocationOnMock invocation) {
+                invocation -> firstSessionCallbacks,
+                invocation -> {
                     PrintJob printJob = (PrintJob) invocation.getArguments()[0];
                     // We pretend the job is handled immediately.
                     printJob.complete();
                     return null;
-                }
-            }, null);
+                }, null);
 
         // Configure the print services.
         FirstPrintService.setCallbacks(firstServiceCallbacks);
         SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
 
         // Create a print adapter that respects the print contract.
-        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
         // Start printing.
         print(adapter);
@@ -98,9 +87,17 @@
         // Wait for write of the first page.
         waitForWriteAdapterCallback(1);
 
+        runOnMainThread(() -> assertFalse(sSession.isDestroyed()));
+        runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
+
         // Select the first printer.
         selectPrinter(FIRST_PRINTER_NAME);
 
+        eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID,
+                sSession.getTrackedPrinters().get(0).getLocalId())));
+        runOnMainThread(() -> assertTrue(sSession.isPrinterDiscoveryStarted()));
+        runOnMainThread(() -> assertEquals(1, sSession.getTrackedPrinters().size()));
+
         // Wait for layout as the printer has different capabilities.
         waitForLayoutAdapterCallbackCount(2);
 
@@ -108,13 +105,17 @@
         // one so no layout should happen).
         selectPrinter(SECOND_PRINTER_NAME);
 
+        eventually(() -> runOnMainThread(() -> assertEquals(SECOND_PRINTER_LOCAL_ID,
+                sSession.getTrackedPrinters().get(0).getLocalId())));
+        runOnMainThread(() -> assertEquals(1, sSession.getTrackedPrinters().size()));
+
         // While the printer discovery session is still alive store the
         // ids of printers as we want to make some assertions about them
         // but only the print service can create printer ids which means
         // that we need to get the created ones.
-        PrinterId firstPrinterId = getAddedPrinterIdForLocalId(firstSessionCallbacks,
+        PrinterId firstPrinterId = getAddedPrinterIdForLocalId(
                 FIRST_PRINTER_LOCAL_ID);
-        PrinterId secondPrinterId = getAddedPrinterIdForLocalId(firstSessionCallbacks,
+        PrinterId secondPrinterId = getAddedPrinterIdForLocalId(
                 SECOND_PRINTER_LOCAL_ID);
         assertNotNull("Coundn't find printer:" + FIRST_PRINTER_LOCAL_ID, firstPrinterId);
         assertNotNull("Coundn't find printer:" + SECOND_PRINTER_LOCAL_ID, secondPrinterId);
@@ -128,6 +129,10 @@
         // Wait for all print jobs to be handled after which the session destroyed.
         waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
 
+        runOnMainThread(() -> assertTrue(sSession.isDestroyed()));
+        runOnMainThread(() -> assertFalse(sSession.isPrinterDiscoveryStarted()));
+        runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
+
         // Verify the expected calls.
         InOrder inOrder = inOrder(firstSessionCallbacks);
 
@@ -159,7 +164,7 @@
         inOrder.verify(firstSessionCallbacks).onDestroy();
     }
 
-    public void testCancelPrintServicesAlertDialog() throws Exception {
+    public void testCancelPrintServicesAlertDialog() throws Throwable {
         if (!supportsPrinting()) {
             return;
         }
@@ -169,20 +174,12 @@
 
         // Create the service callbacks for the first print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return firstSessionCallbacks;
-                    }
-                },
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) {
-                        PrintJob printJob = (PrintJob) invocation.getArguments()[0];
-                        // We pretend the job is handled immediately.
-                        printJob.complete();
-                        return null;
-                    }
+                invocation -> firstSessionCallbacks,
+                invocation -> {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                    // We pretend the job is handled immediately.
+                    printJob.complete();
+                    return null;
                 }, null);
 
         // Configure the print services.
@@ -190,7 +187,7 @@
         SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
 
         // Create a print adapter that respects the print contract.
-        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
         // Start printing.
         print(adapter);
@@ -198,14 +195,22 @@
         // Wait for write of the first page.
         waitForWriteAdapterCallback(1);
 
+        runOnMainThread(() -> assertFalse(sSession.isDestroyed()));
+        runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
+
         // Select the first printer.
         selectPrinter(FIRST_PRINTER_NAME);
 
+        eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID,
+                sSession.getTrackedPrinters().get(0).getLocalId())));
+        runOnMainThread(() -> assertTrue(sSession.isPrinterDiscoveryStarted()));
+        runOnMainThread(() -> assertEquals(1, sSession.getTrackedPrinters().size()));
+
         // While the printer discovery session is still alive store the
         // ids of printers as we want to make some assertions about them
         // but only the print service can create printer ids which means
         // that we need to get the created ones.
-        PrinterId firstPrinterId = getAddedPrinterIdForLocalId(firstSessionCallbacks,
+        PrinterId firstPrinterId = getAddedPrinterIdForLocalId(
                 FIRST_PRINTER_LOCAL_ID);
         assertNotNull("Coundn't find printer:" + FIRST_PRINTER_LOCAL_ID, firstPrinterId);
 
@@ -224,6 +229,10 @@
         // Wait for all print jobs to be handled after which the session destroyed.
         waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
 
+        runOnMainThread(() -> assertTrue(sSession.isDestroyed()));
+        runOnMainThread(() -> assertFalse(sSession.isPrinterDiscoveryStarted()));
+        runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
+
         // Verify the expected calls.
         InOrder inOrder = inOrder(firstSessionCallbacks);
 
@@ -247,7 +256,7 @@
         inOrder.verify(firstSessionCallbacks).onDestroy();
     }
 
-    public void testStartPrinterDiscoveryWithHistoricalPrinters() throws Exception {
+    public void testStartPrinterDiscoveryWithHistoricalPrinters() throws Throwable {
         if (!supportsPrinting()) {
             return;
         }
@@ -257,28 +266,20 @@
 
         // Create the service callbacks for the first print service.
         PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                @Override
-                public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return firstSessionCallbacks;
-                    }
-                },
-                new Answer<Void>() {
-                @Override
-                public Void answer(InvocationOnMock invocation) {
+                invocation -> firstSessionCallbacks,
+                invocation -> {
                     PrintJob printJob = (PrintJob) invocation.getArguments()[0];
                     // We pretend the job is handled immediately.
                     printJob.complete();
                     return null;
-                }
-            }, null);
+                }, null);
 
         // Configure the print services.
         FirstPrintService.setCallbacks(firstServiceCallbacks);
         SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
 
         // Create a print adapter that respects the print contract.
-        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
         // Start printing.
         print(adapter);
@@ -286,9 +287,17 @@
         // Wait for write of the first page.
         waitForWriteAdapterCallback(1);
 
+        runOnMainThread(() -> assertFalse(sSession.isDestroyed()));
+        runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
+
         // Select the first printer.
         selectPrinter(FIRST_PRINTER_NAME);
 
+        eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID,
+                sSession.getTrackedPrinters().get(0).getLocalId())));
+        runOnMainThread(() -> assertTrue(sSession.isPrinterDiscoveryStarted()));
+        runOnMainThread(() -> assertEquals(1, sSession.getTrackedPrinters().size()));
+
         // Wait for a layout to finish - first layout was for the
         // PDF printer, second for the first printer in preview mode.
         waitForLayoutAdapterCallbackCount(2);
@@ -298,7 +307,7 @@
         // but only the print service can create printer ids which means
         // that we need to get the created one.
         PrinterId firstPrinterId = getAddedPrinterIdForLocalId(
-                firstSessionCallbacks, FIRST_PRINTER_LOCAL_ID);
+                FIRST_PRINTER_LOCAL_ID);
 
         // Click the print button.
         clickPrintButton();
@@ -326,11 +335,15 @@
         // Wait for all print jobs to be handled after which the is session destroyed.
         waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
 
+        runOnMainThread(() -> assertTrue(sSession.isDestroyed()));
+        runOnMainThread(() -> assertFalse(sSession.isPrinterDiscoveryStarted()));
+        runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
+
         // Verify the expected calls.
         InOrder inOrder = inOrder(firstSessionCallbacks);
 
         // We start discovery with no printer history.
-        List<PrinterId> priorityList = new ArrayList<PrinterId>();
+        List<PrinterId> priorityList = new ArrayList<>();
         inOrder.verify(firstSessionCallbacks).onStartPrinterDiscovery(
                 priorityList);
 
@@ -371,16 +384,86 @@
         inOrder.verify(firstSessionCallbacks).onDestroy();
     }
 
-    private PrinterId getAddedPrinterIdForLocalId(
-            final PrinterDiscoverySessionCallbacks sessionCallbacks, String printerLocalId) {
-        final List<PrinterInfo> reportedPrinters = new ArrayList<PrinterInfo>();
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                // Grab the printer ids as only the service can create such.
-                StubbablePrinterDiscoverySession session = sessionCallbacks.getSession();
-                reportedPrinters.addAll(session.getPrinters());
-            }
+    public void testAddRemovePrinters() throws Throwable {
+        if (!supportsPrinting()) {
+            return;
+        }
+
+        StubbablePrinterDiscoverySession[] session = new StubbablePrinterDiscoverySession[1];
+
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createMockPrinterDiscoverySessionCallbacks(invocation -> {
+                    session[0] = ((PrinterDiscoverySessionCallbacks)
+                            invocation.getMock()).getSession();
+
+                    onPrinterDiscoverySessionCreateCalled();
+                    return null;
+                }, null, null, null, null, null, invocation -> {
+                    onPrinterDiscoverySessionDestroyCalled();
+                    return null;
+                });
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                invocation -> firstSessionCallbacks, null, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        print(createDefaultPrintDocumentAdapter(1));
+
+        waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+        runOnMainThread(() -> assertEquals(0, session[0].getPrinters().size()));
+
+        PrinterId[] printerIds = new PrinterId[3];
+        runOnMainThread(() -> {
+            printerIds[0] = session[0].getService().generatePrinterId("0");
+            printerIds[1] = session[0].getService().generatePrinterId("1");
+            printerIds[2] = session[0].getService().generatePrinterId("2");
+        });
+
+        PrinterInfo printer1 = (new PrinterInfo.Builder(printerIds[0], "0",
+                PrinterInfo.STATUS_IDLE)).build();
+
+        PrinterInfo printer2 = (new PrinterInfo.Builder(printerIds[1], "1",
+                PrinterInfo.STATUS_IDLE)).build();
+
+        PrinterInfo printer3 = (new PrinterInfo.Builder(printerIds[2], "2",
+                PrinterInfo.STATUS_IDLE)).build();
+
+        ArrayList<PrinterInfo> printers = new ArrayList<>();
+        printers.add(printer1);
+        runOnMainThread(() -> session[0].addPrinters(printers));
+        eventually(() -> runOnMainThread(() -> assertEquals(1, session[0].getPrinters().size())));
+
+        printers.add(printer2);
+        printers.add(printer3);
+        runOnMainThread(() -> session[0].addPrinters(printers));
+        eventually(() -> runOnMainThread(() -> assertEquals(3, session[0].getPrinters().size())));
+
+        ArrayList<PrinterId> printerIdsToRemove = new ArrayList<>();
+        printerIdsToRemove.add(printer1.getId());
+        runOnMainThread(() -> session[0].removePrinters(printerIdsToRemove));
+        eventually(() -> runOnMainThread(() -> assertEquals(2, session[0].getPrinters().size())));
+
+        printerIdsToRemove.add(printer2.getId());
+        printerIdsToRemove.add(printer3.getId());
+        runOnMainThread(() -> session[0].removePrinters(printerIdsToRemove));
+        eventually(() -> runOnMainThread(() -> assertEquals(0, session[0].getPrinters().size())));
+
+        getUiDevice().pressBack();
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
+    private PrinterId getAddedPrinterIdForLocalId(String printerLocalId) throws Throwable {
+        final List<PrinterInfo> reportedPrinters = new ArrayList<>();
+        runOnMainThread(() -> {
+            // Grab the printer ids as only the service can create such.
+            reportedPrinters.addAll(sSession.getPrinters());
         });
 
         final int reportedPrinterCount = reportedPrinters.size();
@@ -400,133 +483,92 @@
     }
 
     private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
-        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                // Get the session.
-                StubbablePrinterDiscoverySession session = ((PrinterDiscoverySessionCallbacks)
-                        invocation.getMock()).getSession();
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            // Get the session.
+            sSession = ((PrinterDiscoverySessionCallbacks)
+                    invocation.getMock()).getSession();
 
-                if (session.getPrinters().isEmpty()) {
-                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+            assertTrue(sSession.isPrinterDiscoveryStarted());
 
-                    // Add the first printer.
-                    PrinterId firstPrinterId = session.getService().generatePrinterId(
-                            FIRST_PRINTER_LOCAL_ID);
-                    PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
-                            FIRST_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
-                        .build();
-                    printers.add(firstPrinter);
+            if (sSession.getPrinters().isEmpty()) {
+                List<PrinterInfo> printers = new ArrayList<>();
 
-                    // Add the first printer.
-                    PrinterId secondPrinterId = session.getService().generatePrinterId(
-                            SECOND_PRINTER_LOCAL_ID);
-                    PrinterInfo secondPrinter = new PrinterInfo.Builder(secondPrinterId,
-                            SECOND_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
-                        .build();
-                    printers.add(secondPrinter);
+                // Add the first printer.
+                PrinterId firstPrinterId = sSession.getService().generatePrinterId(
+                        FIRST_PRINTER_LOCAL_ID);
+                PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
+                        FIRST_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
+                    .build();
+                printers.add(firstPrinter);
 
-                    session.addPrinters(printers);
-                }
-                return null;
+                // Add the first printer.
+                PrinterId secondPrinterId = sSession.getService().generatePrinterId(
+                        SECOND_PRINTER_LOCAL_ID);
+                PrinterInfo secondPrinter = new PrinterInfo.Builder(secondPrinterId,
+                        SECOND_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
+                    .build();
+                printers.add(secondPrinter);
+
+                sSession.addPrinters(printers);
             }
-        }, null, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Get the session.
-                StubbablePrinterDiscoverySession session = ((PrinterDiscoverySessionCallbacks)
-                        invocation.getMock()).getSession();
+            return null;
+        }, invocation -> {
+            assertFalse(sSession.isPrinterDiscoveryStarted());
+            return null;
+        }, null, invocation -> {
+            // Get the session.
+            StubbablePrinterDiscoverySession session = ((PrinterDiscoverySessionCallbacks)
+                    invocation.getMock()).getSession();
 
-                PrinterId trackedPrinterId = (PrinterId) invocation.getArguments()[0];
-                List<PrinterInfo> reportedPrinters = session.getPrinters();
+            PrinterId trackedPrinterId = (PrinterId) invocation.getArguments()[0];
+            List<PrinterInfo> reportedPrinters = session.getPrinters();
 
-                // We should be tracking a printer that we added.
-                PrinterInfo trackedPrinter = null;
-                final int reportedPrinterCount = reportedPrinters.size();
-                for (int i = 0; i < reportedPrinterCount; i++) {
-                    PrinterInfo reportedPrinter = reportedPrinters.get(i);
-                    if (reportedPrinter.getId().equals(trackedPrinterId)) {
-                        trackedPrinter = reportedPrinter;
-                        break;
-                    }
+            // We should be tracking a printer that we added.
+            PrinterInfo trackedPrinter = null;
+            final int reportedPrinterCount = reportedPrinters.size();
+            for (int i = 0; i < reportedPrinterCount; i++) {
+                PrinterInfo reportedPrinter = reportedPrinters.get(i);
+                if (reportedPrinter.getId().equals(trackedPrinterId)) {
+                    trackedPrinter = reportedPrinter;
+                    break;
                 }
-                assertNotNull("Can track only added printers", trackedPrinter);
+            }
+            assertNotNull("Can track only added printers", trackedPrinter);
 
-                // If the printer does not have capabilities reported add them.
-                if (trackedPrinter.getCapabilities() == null) {
+            assertTrue(sSession.getTrackedPrinters().contains(trackedPrinter.getId()));
+            assertEquals(1, sSession.getTrackedPrinters().size());
 
-                    // Add the capabilities to emulate lazy discovery.
-                    // Same for each printer is fine for what we test.
-                    PrinterCapabilitiesInfo capabilities =
-                            new PrinterCapabilitiesInfo.Builder(trackedPrinterId)
-                        .setMinMargins(new Margins(200, 200, 200, 200))
-                        .addMediaSize(MediaSize.ISO_A4, true)
-                        .addMediaSize(MediaSize.ISO_A5, false)
-                        .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
-                        .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                PrintAttributes.COLOR_MODE_COLOR)
-                        .build();
-                    PrinterInfo updatedPrinter = new PrinterInfo.Builder(trackedPrinter)
+            // If the printer does not have capabilities reported add them.
+            if (trackedPrinter.getCapabilities() == null) {
+
+                // Add the capabilities to emulate lazy discovery.
+                // Same for each printer is fine for what we test.
+                PrinterCapabilitiesInfo capabilities =
+                        new PrinterCapabilitiesInfo.Builder(trackedPrinterId)
+                                .setMinMargins(new Margins(200, 200, 200, 200))
+                                .addMediaSize(MediaSize.ISO_A4, true)
+                                .addMediaSize(MediaSize.ISO_A5, false)
+                                .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                        PrintAttributes.COLOR_MODE_COLOR)
+                                .build();
+                PrinterInfo updatedPrinter = new PrinterInfo.Builder(trackedPrinter)
                         .setCapabilities(capabilities)
                         .build();
 
-                    // Update the printer.
-                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
-                    printers.add(updatedPrinter);
-                    session.addPrinters(printers);
-                }
+                // Update the printer.
+                List<PrinterInfo> printers = new ArrayList<>();
+                printers.add(updatedPrinter);
+                session.addPrinters(printers);
+            }
 
-                return null;
-            }
-        }, null, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Take a note onDestroy was called.
-                onPrinterDiscoverySessionDestroyCalled();
-                return null;
-            }
-        });
-    }
+            return null;
+        }, null, null, invocation -> {
+            assertTrue(sSession.isDestroyed());
 
-    public PrintDocumentAdapter createMockPrintDocumentAdapter() {
-        final PrintAttributes[] printAttributes = new PrintAttributes[1];
-
-        return createMockPrintDocumentAdapter(
-            new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
-                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                        .setPageCount(3)
-                        .build();
-                callback.onLayoutFinished(info, false);
-                // Mark layout was called.
-                onLayoutCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Object[] args = invocation.getArguments();
-                PageRange[] pages = (PageRange[]) args[0];
-                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                WriteResultCallback callback = (WriteResultCallback) args[3];
-                writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
-                fd.close();
-                callback.onWriteFinished(pages);
-                // Mark write was called.
-                onWriteCalled();
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Mark finish was called.
-                onFinishCalled();
-                return null;
-            }
+            // Take a note onDestroy was called.
+            onPrinterDiscoverySessionDestroyCalled();
+            return null;
         });
     }
 }
diff --git a/tests/tests/print/src/android/print/cts/PrinterInfoTest.java b/tests/tests/print/src/android/print/cts/PrinterInfoTest.java
index 72f2866..9d691d0 100644
--- a/tests/tests/print/src/android/print/cts/PrinterInfoTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterInfoTest.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Intent;
-import android.graphics.drawable.Icon;
 import android.os.ParcelFileDescriptor;
 import android.print.PageRange;
 import android.print.PrintAttributes;
@@ -38,14 +37,10 @@
 import android.print.cts.services.PrinterDiscoverySessionCallbacks;
 import android.print.cts.services.SecondPrintService;
 import android.print.cts.services.StubbablePrinterDiscoverySession;
-import android.printservice.CustomPrinterIconCallback;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiSelector;
 import android.text.TextUtils;
 
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -53,69 +48,10 @@
  * Tests all allowed types of printerInfo
  */
 public class PrinterInfoTest extends BasePrintTest {
-    private static final int NUM_PAGES = 2;
-
     private static final String NAMED_PRINTERS_NAME_PREFIX = "Printer ";
 
     /** The printer discovery session used in this test */
-    private static StubbablePrinterDiscoverySession mDiscoverySession;
-
-    /** The custom printer icon to use */
-    private Icon mIcon;
-
-    /**
-     * Create a mock {@link PrintDocumentAdapter} that provides {@link #NUM_PAGES} empty pages.
-     *
-     * @return The mock adapter
-     */
-    private PrintDocumentAdapter createMockPrintDocumentAdapter() {
-        final PrintAttributes[] printAttributes = new PrintAttributes[1];
-
-        return createMockPrintDocumentAdapter(
-                new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-                        LayoutResultCallback callback = (LayoutResultCallback) invocation
-                                .getArguments()[3];
-
-                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
-                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
-                                .setPageCount(NUM_PAGES)
-                                .build();
-
-                        callback.onLayoutFinished(info, false);
-
-                        // Mark layout was called.
-                        onLayoutCalled();
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        Object[] args = invocation.getArguments();
-                        PageRange[] pages = (PageRange[]) args[0];
-                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
-                        WriteResultCallback callback = (WriteResultCallback) args[3];
-
-                        writeBlankPages(printAttributes[0], fd, pages[0].getStart(),
-                                pages[0].getEnd());
-                        fd.close();
-                        callback.onWriteFinished(pages);
-
-                        // Mark write was called.
-                        onWriteCalled();
-                        return null;
-                    }
-                }, new Answer<Void>() {
-                    @Override
-                    public Void answer(InvocationOnMock invocation) throws Throwable {
-                        // Mark finish was called.
-                        onFinishCalled();
-                        return null;
-                    }
-                });
-    }
+    private static StubbablePrinterDiscoverySession sDiscoverySession;
 
     private boolean isValidStatus(int status) {
         return status == PrinterInfo.STATUS_IDLE
@@ -130,222 +66,219 @@
      * @return The mock session callbacks
      */
     private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
-        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) {
-                // Get the session.
-                mDiscoverySession = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
-                        .getSession();
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            // Get the session.
+            sDiscoverySession = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
+                    .getSession();
 
-                if (mDiscoverySession.getPrinters().isEmpty()) {
-                    final int INVALID_RES_ID = 0xffffffff;
+            if (sDiscoverySession.getPrinters().isEmpty()) {
+                final int INVALID_RES_ID = 0xffffffff;
 
-                    final PrinterInfo.Builder badPrinter = new PrinterInfo.Builder(
-                            mDiscoverySession.getService().generatePrinterId("bad printer"),
-                            "badPrinter", PrinterInfo.STATUS_UNAVAILABLE);
+                final PrinterInfo.Builder badPrinter = new PrinterInfo.Builder(
+                        sDiscoverySession.getService().generatePrinterId("bad printer"),
+                        "badPrinter", PrinterInfo.STATUS_UNAVAILABLE);
 
-                    String[] localPrinterIds = {
-                            "Printer", null
-                    };
+                String[] localPrinterIds = {
+                        "Printer", null
+                };
 
-                    String[] names = {
-                            NAMED_PRINTERS_NAME_PREFIX, "", null
-                    };
-                    int[] statusList = {
-                            PrinterInfo.STATUS_IDLE, PrinterInfo.STATUS_BUSY,
-                            PrinterInfo.STATUS_UNAVAILABLE, 0, 42
-                    };
-                    int[] iconResourceIds = {
-                            R.drawable.red_printer, 0, INVALID_RES_ID, -1
-                    };
+                String[] names = {
+                        NAMED_PRINTERS_NAME_PREFIX, "", null
+                };
+                int[] statusList = {
+                        PrinterInfo.STATUS_IDLE, PrinterInfo.STATUS_BUSY,
+                        PrinterInfo.STATUS_UNAVAILABLE, 0, 42
+                };
+                int[] iconResourceIds = {
+                        R.drawable.red_printer, 0, INVALID_RES_ID, -1
+                };
 
-                    boolean[] hasCustomPrinterIcons = {
-                            true, false
-                    };
+                boolean[] hasCustomPrinterIcons = {
+                        true, false
+                };
 
-                    String[] descriptions = {
-                            "Description", "", null
-                    };
+                String[] descriptions = {
+                        "Description", "", null
+                };
 
-                    PendingIntent[] infoIntents = {
-                            PendingIntent.getActivity(getActivity(), 0,
-                                    new Intent(getActivity(), Activity.class),
-                                    PendingIntent.FLAG_IMMUTABLE),
-                            null
-                    };
+                PendingIntent[] infoIntents = {
+                        PendingIntent.getActivity(getActivity(), 0,
+                                new Intent(getActivity(), Activity.class),
+                                PendingIntent.FLAG_IMMUTABLE),
+                        null
+                };
 
-                    PrinterCapabilitiesInfo[] capabilityList = {
-                            // The printerId not used in PrinterCapabilitiesInfo
-                            new PrinterCapabilitiesInfo.Builder(mDiscoverySession.getService()
-                                    .generatePrinterId("unused"))
-                                            .setMinMargins(new Margins(200, 200, 200, 200))
-                                            .addMediaSize(MediaSize.ISO_A4, true)
-                                            .addResolution(
-                                                    new Resolution("300x300", "300x300", 300, 300),
-                                                    true)
-                                            .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                                                    PrintAttributes.COLOR_MODE_COLOR)
-                                            .build(),
-                            null
-                    };
+                PrinterCapabilitiesInfo[] capabilityList = {
+                        // The printerId not used in PrinterCapabilitiesInfo
+                        new PrinterCapabilitiesInfo.Builder(sDiscoverySession.getService()
+                                .generatePrinterId("unused"))
+                                        .setMinMargins(new Margins(200, 200, 200, 200))
+                                        .addMediaSize(MediaSize.ISO_A4, true)
+                                        .addResolution(
+                                                new Resolution("300x300", "300x300", 300, 300),
+                                                true)
+                                        .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                                PrintAttributes.COLOR_MODE_COLOR)
+                                        .build(),
+                        null
+                };
 
-                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
-                    for (String localPrinterId : localPrinterIds) {
-                        for (String name : names) {
-                            for (int status : statusList) {
-                                for (int iconResourceId : iconResourceIds) {
-                                    for (boolean hasCustomPrinterIcon : hasCustomPrinterIcons) {
-                                        for (String description : descriptions) {
-                                            for (PendingIntent infoIntent : infoIntents) {
-                                                for (PrinterCapabilitiesInfo capabilities
-                                                        : capabilityList) {
-                                                    // printerId
-                                                    RuntimeException e = null;
-                                                    PrinterId printerId = null;
-                                                    try {
-                                                        if (localPrinterId == null) {
-                                                            printerId = mDiscoverySession
-                                                                    .getService()
-                                                                    .generatePrinterId(
-                                                                            localPrinterId);
-                                                        } else {
-                                                            printerId = mDiscoverySession
-                                                                    .getService()
-                                                                    .generatePrinterId(
-                                                                            localPrinterId
-                                                                                    + printers
-                                                                                            .size());
-                                                        }
-                                                    } catch (RuntimeException ex) {
-                                                        e = ex;
-                                                    }
-
-                                                    // Expect exception if localId is null
+                List<PrinterInfo> printers = new ArrayList<>();
+                for (String localPrinterId : localPrinterIds) {
+                    for (String name : names) {
+                        for (int status : statusList) {
+                            for (int iconResourceId : iconResourceIds) {
+                                for (boolean hasCustomPrinterIcon : hasCustomPrinterIcons) {
+                                    for (String description : descriptions) {
+                                        for (PendingIntent infoIntent : infoIntents) {
+                                            for (PrinterCapabilitiesInfo capabilities
+                                                    : capabilityList) {
+                                                // printerId
+                                                RuntimeException e = null;
+                                                PrinterId printerId = null;
+                                                try {
                                                     if (localPrinterId == null) {
-                                                        if (e == null) {
-                                                            throw new IllegalStateException();
-                                                        }
-                                                    } else if (e != null) {
-                                                        throw e;
+                                                        printerId = sDiscoverySession
+                                                                .getService()
+                                                                .generatePrinterId(
+                                                                        localPrinterId);
+                                                    } else {
+                                                        printerId = sDiscoverySession
+                                                                .getService()
+                                                                .generatePrinterId(
+                                                                        localPrinterId
+                                                                                + printers
+                                                                                        .size());
                                                     }
+                                                } catch (RuntimeException ex) {
+                                                    e = ex;
+                                                }
 
-                                                    // Constructor
-                                                    PrinterInfo.Builder b = null;
-                                                    e = null;
-                                                    try {
-                                                        b = new PrinterInfo.Builder(
-                                                                printerId, name, status);
-                                                    } catch (RuntimeException ex) {
-                                                        e = ex;
-                                                    }
-
-                                                    // Expect exception if any of the parameters was
-                                                    // bad
-                                                    if (printerId == null
-                                                            || TextUtils.isEmpty(name)
-                                                            || !isValidStatus(status)) {
-                                                        if (e == null) {
-                                                            throw new IllegalStateException();
-                                                        } else {
-                                                            b = badPrinter;
-                                                        }
-                                                    } else if (e != null) {
-                                                        throw e;
-                                                    }
-
-                                                    // IconResourceId
-                                                    e = null;
-                                                    try {
-                                                        b.setIconResourceId(iconResourceId);
-                                                    } catch (RuntimeException ex) {
-                                                        e = ex;
-                                                    }
-
-                                                    // Expect exception if iconResourceId was bad
-                                                    // We do allow invalid Ids as the printerInfo
-                                                    // might be created after the package of the
-                                                    // printer is already gone if the printer is a
-                                                    // historical printer.
-                                                    if (iconResourceId < 0) {
-                                                        if (e == null) {
-                                                            throw new IllegalStateException();
-                                                        } else {
-                                                            b = badPrinter;
-                                                        }
-                                                    } else if (e != null) {
-                                                        throw e;
-                                                    }
-
-                                                    // Status
-                                                    e = null;
-                                                    try {
-                                                        b.setStatus(status);
-                                                    } catch (RuntimeException ex) {
-                                                        e = ex;
-                                                    }
-
-                                                    // Expect exception is status is not valid
-                                                    if (!isValidStatus(status)) {
-                                                        if (e == null) {
-                                                            throw new IllegalStateException();
-                                                        } else {
-                                                            b = badPrinter;
-                                                        }
-                                                    } else if (e != null) {
-                                                        throw e;
-                                                    }
-
-                                                    // Name
-                                                    e = null;
-                                                    try {
-                                                        b.setName(name);
-                                                    } catch (RuntimeException ex) {
-                                                        e = ex;
-                                                    }
-
-                                                    // Expect exception if name is empty
-                                                    if (TextUtils.isEmpty(name)) {
-                                                        if (e == null) {
-                                                            throw new IllegalStateException();
-                                                        } else {
-                                                            b = badPrinter;
-                                                        }
-                                                    } else if (e != null) {
-                                                        throw e;
-                                                    }
-
-                                                    // hasCustomPrinterIcon
-                                                    b.setHasCustomPrinterIcon(hasCustomPrinterIcon);
-
-                                                    // Description
-                                                    b.setDescription(description);
-
-                                                    // InfoIntent
-                                                    b.setInfoIntent(infoIntent);
-
-                                                    // Capabilities
-                                                    b.setCapabilities(capabilities);
-
-                                                    PrinterInfo printer = b.build();
-
-                                                    // Don't create bad printers
-                                                    if (b == badPrinter) {
-                                                        continue;
-                                                    }
-
-                                                    // Verify get* methods
-                                                    if (printer.getId() != printerId
-                                                            || printer.getName() != name
-                                                            || printer.getStatus() != status
-                                                            || printer
-                                                                    .getDescription() != description
-                                                            || printer.getCapabilities()
-                                                                    != capabilities) {
+                                                // Expect exception if localId is null
+                                                if (localPrinterId == null) {
+                                                    if (e == null) {
                                                         throw new IllegalStateException();
                                                     }
-
-                                                    printers.add(printer);
+                                                } else if (e != null) {
+                                                    throw e;
                                                 }
+
+                                                // Constructor
+                                                PrinterInfo.Builder b = null;
+                                                e = null;
+                                                try {
+                                                    b = new PrinterInfo.Builder(
+                                                            printerId, name, status);
+                                                } catch (RuntimeException ex) {
+                                                    e = ex;
+                                                }
+
+                                                // Expect exception if any of the parameters was
+                                                // bad
+                                                if (printerId == null
+                                                        || TextUtils.isEmpty(name)
+                                                        || !isValidStatus(status)) {
+                                                    if (e == null) {
+                                                        throw new IllegalStateException();
+                                                    } else {
+                                                        b = badPrinter;
+                                                    }
+                                                } else if (e != null) {
+                                                    throw e;
+                                                }
+
+                                                // IconResourceId
+                                                e = null;
+                                                try {
+                                                    b.setIconResourceId(iconResourceId);
+                                                } catch (RuntimeException ex) {
+                                                    e = ex;
+                                                }
+
+                                                // Expect exception if iconResourceId was bad
+                                                // We do allow invalid Ids as the printerInfo
+                                                // might be created after the package of the
+                                                // printer is already gone if the printer is a
+                                                // historical printer.
+                                                if (iconResourceId < 0) {
+                                                    if (e == null) {
+                                                        throw new IllegalStateException();
+                                                    } else {
+                                                        b = badPrinter;
+                                                    }
+                                                } else if (e != null) {
+                                                    throw e;
+                                                }
+
+                                                // Status
+                                                e = null;
+                                                try {
+                                                    b.setStatus(status);
+                                                } catch (RuntimeException ex) {
+                                                    e = ex;
+                                                }
+
+                                                // Expect exception is status is not valid
+                                                if (!isValidStatus(status)) {
+                                                    if (e == null) {
+                                                        throw new IllegalStateException();
+                                                    } else {
+                                                        b = badPrinter;
+                                                    }
+                                                } else if (e != null) {
+                                                    throw e;
+                                                }
+
+                                                // Name
+                                                e = null;
+                                                try {
+                                                    b.setName(name);
+                                                } catch (RuntimeException ex) {
+                                                    e = ex;
+                                                }
+
+                                                // Expect exception if name is empty
+                                                if (TextUtils.isEmpty(name)) {
+                                                    if (e == null) {
+                                                        throw new IllegalStateException();
+                                                    } else {
+                                                        b = badPrinter;
+                                                    }
+                                                } else if (e != null) {
+                                                    throw e;
+                                                }
+
+                                                // hasCustomPrinterIcon
+                                                b.setHasCustomPrinterIcon(hasCustomPrinterIcon);
+
+                                                // Description
+                                                b.setDescription(description);
+
+                                                // InfoIntent
+                                                b.setInfoIntent(infoIntent);
+
+                                                // Capabilities
+                                                b.setCapabilities(capabilities);
+
+                                                PrinterInfo printer = b.build();
+
+                                                // Don't create bad printers
+                                                if (b == badPrinter) {
+                                                    continue;
+                                                }
+
+                                                // Verify get* methods
+                                                if (printer.getId() != printerId
+                                                        || printer.getName() != name
+                                                        || printer.getStatus() != status
+                                                        || printer
+                                                                .getDescription() != description
+                                                        || printer.getCapabilities()
+                                                                != capabilities) {
+                                                    throw new IllegalStateException();
+                                                }
+
+                                                printers.add(printer);
                                             }
                                         }
                                     }
@@ -353,34 +286,15 @@
                             }
                         }
                     }
-
-                    mDiscoverySession.addPrinters(printers);
                 }
-                return null;
-            }
-        }, null, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                return null;
-            }
-        }, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                CustomPrinterIconCallback callback = (CustomPrinterIconCallback) invocation
-                        .getArguments()[2];
 
-                if (mIcon != null) {
-                    callback.onCustomPrinterIconLoaded(mIcon);
-                }
-                return null;
+                sDiscoverySession.addPrinters(printers);
             }
-        }, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Take a note onDestroy was called.
-                onPrinterDiscoverySessionDestroyCalled();
-                return null;
-            }
+            return null;
+        }, null, null, invocation -> null, invocation -> null, null, invocation -> {
+            // Take a note onDestroy was called.
+            onPrinterDiscoverySessionDestroyCalled();
+            return null;
         });
     }
 
@@ -392,12 +306,7 @@
     private PrintServiceCallbacks createFirstMockPrinterServiceCallbacks(
             final PrinterDiscoverySessionCallbacks sessionCallbacks) {
         return createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return sessionCallbacks;
-                    }
-                },
+                invocation -> sessionCallbacks,
                 null, null);
     }
 
@@ -426,7 +335,7 @@
         SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
 
         // Create a print adapter that respects the print contract.
-        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
         // Start printing.
         print(adapter);
diff --git a/tests/tests/print/src/android/print/cts/Utils.java b/tests/tests/print/src/android/print/cts/Utils.java
new file mode 100644
index 0000000..93f5632
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/Utils.java
@@ -0,0 +1,148 @@
+/*
+ * 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.print.cts;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.print.PrintJob;
+import android.print.PrintManager;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+/**
+ * Utilities for print tests
+ */
+public class Utils {
+    private static final String LOG_TAG = "Utils";
+
+    /**
+     * A {@link Runnable} that can throw an {@link Throwable}.
+     */
+    public interface Invokable {
+        void run() throws Throwable;
+    }
+
+    /**
+     * Run a {@link Invokable} and expect and {@link Throwable} of a certain type.
+     *
+     * @param r             The {@link Invokable} to run
+     * @param expectedClass The expected {@link Throwable} type
+     */
+    public static void assertException(@NonNull Invokable r,
+            @NonNull Class<? extends Throwable> expectedClass) throws Throwable {
+        try {
+            r.run();
+        } catch (Throwable e) {
+            if (e.getClass().isAssignableFrom(expectedClass)) {
+                return;
+            } else {
+                Log.e(LOG_TAG, "Expected: " + expectedClass.getName() + ", got: "
+                        + e.getClass().getName());
+                throw e;
+            }
+        }
+
+        throw new AssertionError("No throwable thrown");
+    }
+
+    /**
+     * Run a {@link Invokable} on the main thread and forward the {@link Throwable} if one was
+     * thrown.
+     *
+     * @param r The {@link Invokable} to run
+     *
+     * @throws Throwable If the {@link Runnable} caused an issue
+     */
+    static void runOnMainThread(@NonNull final Invokable r) throws Throwable {
+        final Object synchronizer = new Object();
+        final Throwable[] thrown = new Throwable[1];
+
+        synchronized (synchronizer) {
+            (new Handler(Looper.getMainLooper())).post(() -> {
+                synchronized (synchronizer) {
+                    try {
+                        r.run();
+                    } catch (Throwable t) {
+                        thrown[0] = t;
+                    }
+
+                    synchronizer.notify();
+                }
+            });
+
+            synchronizer.wait();
+        }
+
+        if (thrown[0] != null) {
+            throw thrown[0];
+        }
+    }
+
+    /**
+     * Make sure that a {@link Invokable} eventually finishes without throwing a {@link Throwable}.
+     *
+     * @param r The {@link Invokable} to run.
+     */
+    public static void eventually(@NonNull Invokable r) throws Throwable {
+        long start = System.currentTimeMillis();
+
+        while (true) {
+            try {
+                r.run();
+                break;
+            } catch (Throwable e) {
+                if (System.currentTimeMillis() - start < BasePrintTest.OPERATION_TIMEOUT_MILLIS) {
+                    Log.e(LOG_TAG, "Ignoring exception", e);
+
+                    try {
+                        Thread.sleep(500);
+                    } catch (InterruptedException e1) {
+                        Log.e(LOG_TAG, "Interrupted", e);
+                    }
+                } else {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    /**
+     * @param name Name of print job
+     *
+     * @return The print job for the name
+     *
+     * @throws Exception If print job could not be found
+     */
+    static @NonNull PrintJob getPrintJob(@NonNull PrintManager pm, @NonNull String name)
+            throws Exception {
+        for (android.print.PrintJob job : pm.getPrintJobs()) {
+            if (job.getInfo().getLabel().equals(name)) {
+                return job;
+            }
+        }
+
+        throw new Exception("Print job " + name + " not found in " + pm.getPrintJobs());
+    }
+
+    /**
+     * @return The print manager
+     */
+    static @NonNull PrintManager getPrintManager(@NonNull Context context) {
+        return (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
+    }
+}
diff --git a/tests/tests/print/src/android/print/cts/services/CustomPrintOptionsActivity.java b/tests/tests/print/src/android/print/cts/services/CustomPrintOptionsActivity.java
index dd5ac44..cf52ece 100644
--- a/tests/tests/print/src/android/print/cts/services/CustomPrintOptionsActivity.java
+++ b/tests/tests/print/src/android/print/cts/services/CustomPrintOptionsActivity.java
@@ -28,7 +28,7 @@
  */
 public class CustomPrintOptionsActivity extends Activity {
     /** Lock for {@link #sCallback} */
-    private static Object sLock = new Object();
+    private static final Object sLock = new Object();
 
     /** Currently registered callback for _both_ first and second print service. */
     private static CustomPrintOptionsCallback sCallback = null;
diff --git a/tests/tests/print/src/android/print/cts/services/PrintServiceCallbacks.java b/tests/tests/print/src/android/print/cts/services/PrintServiceCallbacks.java
index ff0245f..749e8a9 100644
--- a/tests/tests/print/src/android/print/cts/services/PrintServiceCallbacks.java
+++ b/tests/tests/print/src/android/print/cts/services/PrintServiceCallbacks.java
@@ -17,17 +17,16 @@
 package android.print.cts.services;
 
 import android.printservice.PrintJob;
-import android.printservice.PrintService;
 
 public abstract class PrintServiceCallbacks {
 
-    private PrintService mService;
+    private StubbablePrintService mService;
 
-    public PrintService getService() {
+    public StubbablePrintService getService() {
         return mService;
     }
 
-    public void setService(PrintService service) {
+    public void setService(StubbablePrintService service) {
         mService = service;
     }
 
diff --git a/tests/tests/print/src/android/print/cts/services/StubbablePrintService.java b/tests/tests/print/src/android/print/cts/services/StubbablePrintService.java
index 2686b41..8c3b89b 100644
--- a/tests/tests/print/src/android/print/cts/services/StubbablePrintService.java
+++ b/tests/tests/print/src/android/print/cts/services/StubbablePrintService.java
@@ -16,10 +16,13 @@
 
 package android.print.cts.services;
 
+import android.content.Context;
 import android.printservice.PrintJob;
 import android.printservice.PrintService;
 import android.printservice.PrinterDiscoverySession;
 
+import java.util.List;
+
 public abstract class StubbablePrintService extends PrintService {
 
     @Override
@@ -49,4 +52,13 @@
     }
 
     protected abstract PrintServiceCallbacks getCallbacks();
+
+    public void callAttachBaseContext(Context base) {
+        attachBaseContext(base);
+    }
+
+    public List<PrintJob> callGetActivePrintJobs() {
+        return getActivePrintJobs();
+    }
+
 }
diff --git a/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java b/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
index b7cccaa..e0ec1c1 100644
--- a/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
+++ b/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
@@ -16,6 +16,7 @@
 
 package android.print.cts.services;
 
+import android.support.annotation.NonNull;
 import android.os.CancellationSignal;
 import android.print.PrinterId;
 import android.printservice.CustomPrinterIconCallback;
@@ -42,7 +43,7 @@
     }
 
     @Override
-    public void onStartPrinterDiscovery(List<PrinterId> priorityList) {
+    public void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList) {
         if (mCallbacks != null) {
             mCallbacks.onStartPrinterDiscovery(priorityList);
         }
@@ -56,29 +57,30 @@
     }
 
     @Override
-    public void onValidatePrinters(List<PrinterId> printerIds) {
+    public void onValidatePrinters(@NonNull List<PrinterId> printerIds) {
         if (mCallbacks != null) {
             mCallbacks.onValidatePrinters(printerIds);
         }
     }
 
     @Override
-    public void onStartPrinterStateTracking(PrinterId printerId) {
+    public void onStartPrinterStateTracking(@NonNull PrinterId printerId) {
         if (mCallbacks != null) {
             mCallbacks.onStartPrinterStateTracking(printerId);
         }
     }
 
     @Override
-    public void onRequestCustomPrinterIcon(PrinterId printerId,
-            CancellationSignal cancellationSignal, CustomPrinterIconCallback callback) {
+    public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
+            @NonNull CancellationSignal cancellationSignal,
+            @NonNull CustomPrinterIconCallback callback) {
         if (mCallbacks != null) {
             mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback);
         }
     }
 
     @Override
-    public void onStopPrinterStateTracking(PrinterId printerId) {
+    public void onStopPrinterStateTracking(@NonNull PrinterId printerId) {
         if (mCallbacks != null) {
             mCallbacks.onStopPrinterStateTracking(printerId);
         }
diff --git a/tests/tests/print/src/android/print/pdf/cts/PrintedPdfDocumentTest.java b/tests/tests/print/src/android/print/pdf/cts/PrintedPdfDocumentTest.java
new file mode 100644
index 0000000..b34c8cc
--- /dev/null
+++ b/tests/tests/print/src/android/print/pdf/cts/PrintedPdfDocumentTest.java
@@ -0,0 +1,191 @@
+/*
+ * 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.print.pdf.cts;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.pdf.PdfDocument;
+import android.print.PrintAttributes;
+import android.print.pdf.PrintedPdfDocument;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.print.cts.Utils.assertException;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link PrintedPdfDocument}. This class is a subclass of {@link PdfDocument}, hence only the
+ * overridden methods are tested.
+ */
+@RunWith(AndroidJUnit4.class)
+public class PrintedPdfDocumentTest {
+    private static final PrintAttributes.Margins ZERO_MARGINS = new PrintAttributes.Margins(0, 0, 0,
+            0);
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    @Test
+    public void createWithNullAttributes() throws Throwable {
+        assertException(() -> new PrintedPdfDocument(mContext, null), NullPointerException.class);
+    }
+
+    @Test
+    public void createWithNullMediaSize() throws Throwable {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS).build();
+        assertException(() -> new PrintedPdfDocument(mContext, attr),
+                NullPointerException.class);
+    }
+
+    @Test
+    public void createWithNullMargins() throws Throwable {
+        PrintAttributes attr = new PrintAttributes.Builder()
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+        assertException(() -> new PrintedPdfDocument(mContext, attr),
+                NullPointerException.class);
+    }
+
+    @Test
+    public void createWithNullContext() throws Exception {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS)
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+
+        // Legacy: Context is not used and not checked for null-ness
+        PrintedPdfDocument doc = new PrintedPdfDocument(null, attr);
+        doc.close();
+    }
+
+    @Test
+    public void startPage() throws Exception {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS)
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+
+        PrintedPdfDocument doc = new PrintedPdfDocument(mContext, attr);
+        PdfDocument.Page page = doc.startPage(0);
+        doc.finishPage(page);
+        doc.close();
+    }
+
+    @Test
+    public void oneMilPageSize() throws Throwable {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS)
+                .setMediaSize(new PrintAttributes.MediaSize("oneMil", "oneMil", 1, 1)).build();
+
+        PrintedPdfDocument doc = new PrintedPdfDocument(mContext, attr);
+
+        // We get an illegal argument exception here as a single mil of page size is converted to 0
+        // pts.
+        assertEquals(0, milsToPts(attr.getMediaSize().getHeightMils()));
+        assertException(() -> doc.startPage(0), IllegalArgumentException.class);
+
+        doc.close();
+    }
+
+    /**
+     * Converts mils (1000th of an inch) to postscript points (72th of an inch).
+     *
+     * @param mils The distance in mils
+     *
+     * @return The distance in Postscript points
+     */
+    private int milsToPts(int mils) {
+        return (int) (((float) mils / 1000) * 72);
+    }
+
+    @Test
+    public void getPageWidth() throws Exception {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS)
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+
+        PrintedPdfDocument doc = new PrintedPdfDocument(mContext, attr);
+        assertEquals(milsToPts(attr.getMediaSize().getWidthMils()), doc.getPageWidth());
+        doc.close();
+    }
+
+    @Test
+    public void getPageHeight() throws Exception {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS)
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+
+        PrintedPdfDocument doc = new PrintedPdfDocument(mContext, attr);
+        assertEquals(milsToPts(attr.getMediaSize().getHeightMils()), doc.getPageHeight());
+        doc.close();
+    }
+
+    @Test
+    public void getContentRect() throws Exception {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS)
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+
+        PrintedPdfDocument doc = new PrintedPdfDocument(mContext, attr);
+        assertEquals(new Rect(0, 0, milsToPts(attr.getMediaSize().getWidthMils()),
+                milsToPts(attr.getMediaSize().getHeightMils())), doc.getPageContentRect());
+        doc.close();
+    }
+
+    @Test
+    public void getContentRectBigMargins() throws Exception {
+        PrintAttributes.Margins margins = new PrintAttributes.Margins(50, 60, 70, 80);
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(margins)
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+
+        PrintedPdfDocument doc = new PrintedPdfDocument(mContext, attr);
+        assertEquals(new Rect(milsToPts(margins.getLeftMils()), milsToPts(margins.getTopMils()),
+                        milsToPts(attr.getMediaSize().getWidthMils()) - milsToPts(margins.getRightMils()),
+                        milsToPts(attr.getMediaSize().getHeightMils()) -
+                                milsToPts(margins.getBottomMils())),
+                doc.getPageContentRect());
+        doc.close();
+    }
+
+    @Test
+    public void getPageHeightAfterClose() throws Exception {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS)
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+
+        PrintedPdfDocument doc = new PrintedPdfDocument(mContext, attr);
+        doc.close();
+        assertEquals(milsToPts(attr.getMediaSize().getHeightMils()), doc.getPageHeight());
+    }
+
+    @Test
+    public void getPageWidthAfterClose() throws Exception {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS)
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+
+        PrintedPdfDocument doc = new PrintedPdfDocument(mContext, attr);
+        doc.close();
+        assertEquals(milsToPts(attr.getMediaSize().getWidthMils()), doc.getPageWidth());
+    }
+
+    @Test
+    public void getContentRectAfterClose() throws Exception {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS)
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+
+        PrintedPdfDocument doc = new PrintedPdfDocument(mContext, attr);
+        doc.close();
+        assertEquals(new Rect(0, 0, milsToPts(attr.getMediaSize().getWidthMils()),
+                milsToPts(attr.getMediaSize().getHeightMils())), doc.getPageContentRect());
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java
index f8f610a..0c6f411 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java
@@ -29,6 +29,7 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
 import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
 import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
 import android.provider.cts.contacts.ContactUtil;
@@ -228,6 +229,15 @@
                 new long[]{contact.getId()}
         );
 
+        // Contacts.CONTENT_FILTER_URI
+        DatabaseAsserts.checkProjection(mResolver,
+                Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon().appendEncodedPath("xxx")
+                        .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                                String.valueOf(Directory.DEFAULT)).build(),
+                PROJECTION,
+                new long[]{contact.getId()}
+        );
+
         // Contacts.CONTENT_LOOKUP_URI
         DatabaseAsserts.checkProjection(mResolver,
                 Contacts.getLookupUri(contactId, lookupKey),
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_DataTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_DataTest.java
index 33d3a28..62c6fdd 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_DataTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_DataTest.java
@@ -36,6 +36,7 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Contacts.Entity;
 import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Directory;
 import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.RawContactsEntity;
 import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
@@ -533,6 +534,37 @@
         assertCursorStoredValuesWithRawContactsFilter(uri, ids, sContentValues[6]);
     }
 
+    public void testEnterpriseCallableFilterByNameOrOrganization_returnsCorrectDataRows()
+            throws Exception {
+        long[] ids = setupContactablesTestData();
+        Uri uri = Uri.withAppendedPath(Callable.ENTERPRISE_CONTENT_FILTER_URI, "doe").buildUpon()
+                .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT))
+                .build();
+        // Only callables belonging to John Doe (name) and Cold Tamago (organization) are returned.
+        assertCursorStoredValuesWithRawContactsFilter(uri, ids, sContentValues[5],
+                sContentValues[6]);
+    }
+
+    public void testEnterpriseCallableFilterByNumber_returnsCorrectDataRows() throws Exception {
+        long[] ids = setupContactablesTestData();
+        Uri uri = Uri.withAppendedPath(Callable.ENTERPRISE_CONTENT_FILTER_URI, "510").buildUpon()
+                .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT))
+                .build();
+        assertCursorStoredValuesWithRawContactsFilter(uri, ids, sContentValues[1]);
+    }
+
+    public void testEnterpriseCallableFilterBySipAddress_returnsCorrectDataRows()
+            throws Exception {
+        long[] ids = setupContactablesTestData();
+        Uri uri = Uri.withAppendedPath(Callable.ENTERPRISE_CONTENT_FILTER_URI, "mysip").buildUpon()
+                .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT))
+                .build();
+        assertCursorStoredValuesWithRawContactsFilter(uri, ids, sContentValues[6]);
+    }
+
     public void testDataInsert_updatesContactLastUpdatedTimestamp() {
         DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
         long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_SearchSnippetsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_SearchSnippetsTest.java
index 847e357..b049996 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_SearchSnippetsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_SearchSnippetsTest.java
@@ -28,6 +28,7 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
 import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.SearchSnippets;
 import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
@@ -85,6 +86,15 @@
         assertCursorStoredValuesWithContactsFilter(uri, ids);
     }
 
+    public void testEnterpriseSearchSnippets_NoMatch() throws Exception {
+        long[] ids = setupTestData();
+        final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+                .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT)).appendPath("nomatch").build();
+
+        assertCursorStoredValuesWithContactsFilter(uri, ids);
+    }
+
     public void testSearchSnippets_MatchEmailAddressCorrectSnippet() throws Exception {
         long[] ids = setupTestData();
         final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -96,6 +106,18 @@
         assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
     }
 
+    public void testEnterpriseSearchSnippets_MatchEmailAddressCorrectSnippet() throws Exception {
+        long[] ids = setupTestData();
+        final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+                .appendPath("farm").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT)).build();
+
+        final ContentValues expected = new ContentValues();
+        expected.put(Contacts._ID, ids[1]);
+        expected.put(SearchSnippets.SNIPPET, "eggs@[farmers].org");
+        assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+    }
+
     public void testSearchSnippets_MatchPhoneNumberCorrectSnippet() throws Exception {
         long[] ids = setupTestData();
         final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -107,6 +129,18 @@
         assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
     }
 
+    public void testEnterpriseSearchSnippets_MatchPhoneNumberCorrectSnippet() throws Exception {
+        long[] ids = setupTestData();
+        final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+                .appendPath("510").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT)).build();
+
+        final ContentValues expected = new ContentValues();
+        expected.put(Contacts._ID, ids[0]);
+        expected.put(SearchSnippets.SNIPPET, "[510-123-5769]");
+        assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+    }
+
     public void testSearchSnippets_MatchPostalAddressCorrectSnippet() throws Exception {
         long[] ids = setupTestData();
         final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -118,6 +152,18 @@
         assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
     }
 
+    public void testEnterpriseSearchSnippets_MatchPostalAddressCorrectSnippet() throws Exception {
+        long[] ids = setupTestData();
+        final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+                .appendPath("street").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT)).build();
+
+        final ContentValues expected = new ContentValues();
+        expected.put(Contacts._ID, ids[2]);
+        expected.put(SearchSnippets.SNIPPET, "123 Main [Street] Unit 3113\u2026");
+        assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+    }
+
     public void testSearchSnippets_LongMatchTruncation() throws Exception {
         long[] ids = setupTestData();
         final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -129,6 +175,18 @@
         assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
     }
 
+    public void testEnterpriseSearchSnippets_LongMatchTruncation() throws Exception {
+        long[] ids = setupTestData();
+        final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+                .appendPath("over").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT)).build();
+
+        final ContentValues expected = new ContentValues();
+        expected.put(Contacts._ID, ids[2]);
+        expected.put(SearchSnippets.SNIPPET, "\u2026dog jumps [over] the quick\u2026");
+        assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+    }
+
     public void testSearchSnippets_MultipleMatchesCorrectSnippet() throws Exception {
         long[] ids = setupTestData();
         final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -145,6 +203,23 @@
         assertCursorStoredValuesWithContactsFilter(uri, ids, expected, expected2);
     }
 
+    public void testEnterpriseSearchSnippets_MultipleMatchesCorrectSnippet() throws Exception {
+        long[] ids = setupTestData();
+        final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+                .appendPath("123").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT)).build();
+
+        final ContentValues expected = new ContentValues();
+        expected.put(Contacts._ID, ids[1]);
+        expected.put(SearchSnippets.SNIPPET, "[123-456-7890]");
+
+        final ContentValues expected2 = new ContentValues();
+        expected2.put(Contacts._ID, ids[2]);
+        expected2.put(SearchSnippets.SNIPPET, "[123] Main Street Unit 3113\u2026");
+
+        assertCursorStoredValuesWithContactsFilter(uri, ids, expected, expected2);
+    }
+
     /**
      * Tests that if deferred snippeting is indicated, the provider will not perform formatting
      * of the snippet for a single word query.
@@ -163,6 +238,25 @@
     }
 
     /**
+     * Tests that if deferred snippeting is indicated, the provider will not perform formatting
+     * of the snippet for a single word query.
+     */
+    public void testEnterpriseSearchSnippets_DeferredSnippetingSingleWordQuerySnippetDeferred()
+            throws Exception {
+        long[] ids = setupTestData();
+        final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+                .appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1")
+                .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT))
+                .appendPath("510").build();
+
+        final ContentValues expected = new ContentValues();
+        expected.put(Contacts._ID, ids[0]);
+        expected.put(SearchSnippets.SNIPPET, "510-123-5769");
+        assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+    }
+
+    /**
      * Tests that even if deferred snippeting is indicated, a multi-word query will have formatting
      * of the snippet done by the provider using SQLite
      */
@@ -180,6 +274,25 @@
     }
 
     /**
+     * Tests that even if deferred snippeting is indicated, a multi-word query will have formatting
+     * of the snippet done by the provider using SQLite
+     */
+    public void testEnterpriseSearchSnippets_DeferredSnippetingMultiWordQuerySnippetNotDeferred()
+            throws Exception {
+        long[] ids = setupTestData();
+        final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+                .appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1")
+                .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT))
+                .appendPath("jumps over").build();
+
+        final ContentValues expected = new ContentValues();
+        expected.put(Contacts._ID, ids[2]);
+        expected.put(SearchSnippets.SNIPPET, "\u2026lazy dog [jumps] [over] the\u2026");
+        assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+    }
+
+    /**
      * Given a uri, performs a query on the contacts provider for that uri and asserts that the
      * cursor returned from the query matches the expected results.
      *
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs b/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
index d731561..d5f7099 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
@@ -67,17 +67,17 @@
   me.val = in;
   me.idx = x;
 
-  if (me.val < accum->min.val)
+  if (me.val <= accum->min.val)
     accum->min = me;
-  if (me.val > accum->max.val)
+  if (me.val >= accum->max.val)
     accum->max = me;
 }
 
 static void fMMCombiner(MinAndMax *accum,
                         const MinAndMax *val) {
-  if (val->min.val < accum->min.val)
+  if ((accum->min.idx < 0) || (val->min.val < accum->min.val))
     accum->min = val->min;
-  if (val->max.val > accum->max.val)
+  if ((accum->max.idx < 0) || (val->max.val > accum->max.val))
     accum->max = val->max;
 }
 
@@ -428,8 +428,32 @@
 /////////////////////////////////////////////////////////////////////////
 
 // Test out-of-range result.
+
+// When a result is ulong, it can take on values not representable on
+// the Java side, where there are no unsigned integral types and long
+// is the largest integral type -- i.e., all values in the range
+// (MAX_LONG, MAX_ULONG] are not representable in Java.  The reflected
+// result_*.get() methods throw an exception if the result value is
+// out of range.  The globals and reduction kernels below allow a test
+// case on the Java side to describe what kind of result we should
+// produce -- in particular, what to use for an in-range value and an
+// out-of-range value, and where (if anywhere) to put an out-of-range
+// value within the result (which might be scalar, vector, array of
+// scalar, or array of vector).
+
 // We don't care about the input at all.
 // We use these globals to configure the generation of the result.
+// A kernel puts 2*oorrBadResultHalf in the position (if any) of the result
+// given by oorrBadResult, and oorrGoodResult everywhere else.
+// The oorrBadPos encoding is as follows:
+// - For scalar result, 0 = scalar; anything else = nowhere
+// - For vector result, 0..length(vector)-1 = corresponding vector component
+//     (0 = x, 1 = y, 2 = z, 3 = w); anything else = nowhere
+// - For array of scalar result, 0..length(array)-1 = corresponding array element;
+//     anything else = nowhere
+// - For array of vector result, 0..length(vector)*length(array)-1 = corresponding
+//     vector component C of corresponding array element E; anything else = nowhere
+//     (encoding is C + length(vector)*E)
 ulong oorrGoodResult;     // the value of a good result
 ulong oorrBadResultHalf;  // half the value of a bad result
                           //   ("half" because Java can only set the global from long not from ulong)
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 7a67b08..1423aca 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -37,6 +37,14 @@
 
         <service android:name="android.security.cts.activity.SecureRandomService"
                  android:process=":secureRandom"/>
+        <activity
+            android:name="android.security.cts.DisplayDriverActivity"
+            android:label="Test qhwc::MDPCompLowRes::allocLayerPipes (Qualcomm)">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+            </intent-filter>
+        </activity>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/res/layout/activity_displaydriver.xml b/tests/tests/security/res/layout/activity_displaydriver.xml
new file mode 100755
index 0000000..9009dbf
--- /dev/null
+++ b/tests/tests/security/res/layout/activity_displaydriver.xml
@@ -0,0 +1,34 @@
+<?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.

+ -->

+<LinearLayout

+    xmlns:android="http://schemas.android.com/apk/res/android"

+    android:layout_width="fill_parent"

+    android:layout_height="fill_parent"

+    android:gravity="center"

+    android:orientation="vertical">

+

+    <VideoView

+        android:id="@+id/videoview"

+        android:layout_width="300dp"

+        android:layout_height="250dp"

+        android:layout_gravity="center"/>

+

+</LinearLayout>

+

+

+

+

diff --git a/tests/tests/security/res/raw/blacklist_test_chain.pem b/tests/tests/security/res/raw/blacklist_test_chain.pem
new file mode 100644
index 0000000..6f1f297
--- /dev/null
+++ b/tests/tests/security/res/raw/blacklist_test_chain.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIICxzCCAa+gAwIBAgIDAopPMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwDzENMAsGA1UEAxMEbGVhZjCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAOA1rNFofKivnO6f/UjNnkUZX4qG+MBXw5eeingfrLrAbyTP
+qf/YCN3F8JOcot1QUEojcjIrm54rDgi1+o9qDDY0CfbJ8UGmjgh0h5odlxnZbsF2
+0Tzy3lEFHPUUBj6160itB95giHDKH1meW91L1ah8Z+nWES9GGBIAS/1XpeXtiE7/
+IuVmEuE8veAbwdMC9qRSEeq2zUWhA4m/KzTuli/GNErkXlazj3hlBs5WJ207ztTp
+HRGrAEjQgRKb3Ap2leowiE/u9D1Ean53g4v4gzDV1gx5uTZ395WfuWteO9ZUc9bo
+XMeGJiPcvyr2i8Do25ZWw+wW1T2TbcEAtyfOmgkCAwEAAaMTMBEwDwYDVR0TAQH/
+BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAPY6VDC0kfY+kGrM5YiNEjs6PjNjj
+ojWU5/UMjwfRqF8JtkNnV9LnBiNlNGUIV8b5OCyXKGjDlc+ISNRvpgGbZ4dzVIwE
+OKKL9tUB4IFwRAxO0UbLtVkwFeX3clzTezLkei7ahgUe04c2ZjFeO/mf/nuQWvWY
+hprLz5uiGtKWPcirec4wPLkuyHzQMv7Dx/5VYARuxhHkkplteVQ4k9nTxag372Re
+eHgH4KKgLTXEBjV55RoAtOsug+k+KT8U9FzU2ul/j+89tJihllkD1udqIkic8RMx
+qn/mBaIe/ENb88TzrSXcp2xE9rth+QtjpNAVGnE4hP87QukVgedq7JKV7Q==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC1DCCAbygAwIBAgIDDYaqMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwHDEaMBgGA1UEAxMRYmxhY2tsaXN0IHRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDafYp6+Gs5ZjfLfU2EH/NYpvdBUyPz
+veQBJCE4PhBYhOm+Z+J6aX0rSHqU4VTJ8H0TOb6Fh54zBUkIQJHx8YTIsXVmDj0O
+louWAa3uYpIOeBz46knJxdTI9NG6XnsHMYUICZPM8CHtHhoaYnhaRFTcGIg+Y9Hl
+BxMTYXXtqjicg10YuSuEkwMuDT7CbmnmYon8Gt5+ygHIe8YFWdCicpzm5wlPvRu4
+D+WiH2mTgfFG5D5QDoRnxnHWAcO8/+UenFtnbfRip9h6TrzXoJSHtuYW3rMCDVG3
+owVwUE3+ExMcbWKn+qaqGQsjrLlwyYEcKjhH67iPFcTtvZfCsgv8YG75AgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAILNS2XgO4Qa
+plyF7wbQFvVlFFe1QIiEiPZcopqb0zEse73IPBGUnoIt3C9keCv8Q6d7h0x2fe2N
+IqD4P9WXGQYiobBnTci1d2nW5dBq1WVDcpK4cNVsDX7SBE6sd19JEAazNSPIQJ6T
+sts2JXXdTssAyVqGAnq6TwQ2U5ArzuC5pCmr7FcfYAH0sCZM5VWw+ffJylDMBfeG
+oWyjH6f+TmkDd7yvIDh+ptn7Qv+LRxIjHDLPOxG9Y6JaDYtVqKJWh7er5/HFlwUi
+E6gpIuFM6It5ogUtmik2B19bPWpcnGFhv01IKBgmihpzd8LyCmxTtkK11KMxS1JF
+xZSCP3mJTbQ=
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/res/raw/blacklist_test_valid_ca.pem b/tests/tests/security/res/raw/blacklist_test_valid_ca.pem
new file mode 100644
index 0000000..19148c7
--- /dev/null
+++ b/tests/tests/security/res/raw/blacklist_test_valid_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwDCCAaigAwIBAgIDBWa1MA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMTB1Rl
+c3QgQ2EwKhgTMjAxNTAxMDEwMDAwMDArMDAwMBgTMjAyNTAxMDEwMDAwMDArMDAw
+MDASMRAwDgYDVQQDEwdUZXN0IENhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAuk5Hq/uHOz7E3gEZFXKb0ZFslODflO7vB/VT3dmHyGXxuDK5fgQB4xPz
+uoU1VSpD9Pxpe9u+6jNlShEZ5xN34c2F6g+stU4lUS5udqCZVEtB6/etOOpMuiWU
+Ud2DVkEAn9weWkJmKy2gkLQ8p2Iw+0mPlhKKFI9brhGTEpQDTvW9sbLmSQFSEk30
+Ia5rxii/cgu8j5AQmsvUQA06vHXq6/xIsQIj1UFMycBmPz8BvrVO/c891vD9f2Uq
+gQg4p084rmsc6a7PAhBibTOFs3m91HNyZuY2M3pA1r1oLPRQ3WYXb8Wt+kHVtKAr
+L6qDXtofCU3RGhAruwjmuOWftgNsGwIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/
+MA0GCSqGSIb3DQEBCwUAA4IBAQCkFKi9HmsOyn4Wh6RpzwSh39L6e48IdOMcNpOK
+O38tO2rO/uNnhGn2ptnUJkwYS7XOy/A09q1iZNbiuwBweIxc8Z17vpNmk7cF4TMw
+lMRJjDE3Dm2qjTs/lDOknGuzB38Q8tGN/ZbYUHjjf4TZHk5FXCzRUUp+UMzxlOuc
+HAuNuBlQUW88s26h7NdNr115VCbouAI7YkWJRmS2FbeQD5Nwx/kZcvLtJyKasx+n
+imeqy3kCW1NzP9nwlsx2vwW6ydGsdHxqsfrRpdRSLHjzQDA+5m5xMNV0oTr86Iex
+mkqHtIMbOOUpzrE3PACA4m7IgA6AcSkV5gGM9AgqcYccC3St
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/res/raw/blacklist_test_valid_chain.pem b/tests/tests/security/res/raw/blacklist_test_valid_chain.pem
new file mode 100644
index 0000000..e763a05
--- /dev/null
+++ b/tests/tests/security/res/raw/blacklist_test_valid_chain.pem
@@ -0,0 +1,87 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaqgAwIBAgIDD37fMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNVBAMTDGlu
+dGVybWVkaWF0ZTAqGBMyMDE1MDEwMTAwMDAwMCswMDAwGBMyMDI1MDEwMTAwMDAw
+MCswMDAwMA8xDTALBgNVBAMTBGxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDNq1OWpxGZfNFw8E8ZPvYEXeaXEa1twBSKDe1EUctuck+F8Ethb0O1
+ooWA9egJh8GWSbxFdPfoJ/yyuor3sH5kkUtq94NO/1IXPn4xnrwrfvkeVR8e3pXn
+kAQm7MH8c8iPmQ59arfBjFfX9ZZhPiLDPq1bsQa8WqaajyylVVDzQcYseDSHoR/7
+3QmcfUZjH5qxYf7jcS8QdtfnD6faZuczM30qL7N3BLn2gcA5I5jVkrxQBKfLBPfl
+6k3aO6ekxSSxhSHqBv7x5VIzoiq666DGdelLuwrmMksx7Ni7cnXws3rlBYCr6wly
+Hux62YJ9Og3rC5lb3pjkmSzj31VVfFnpAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB
+Af8wDQYJKoZIhvcNAQELBQADggEBAISuXogfdMHZiAs3CJwsOTjCLW0MGsqWH88j
+wdkbotZuTAb84Iq2vpoX/w95WlyakseFGHnAaexy4nzSNyn8LC5b4JMNQopn8Gxs
+y3p0Z+XC/PNC/4lVxQB8KARFvhtW7Ltw1jjIqbTq2ZTWVSCuqb+1ZnMihP4MYinb
+Ml/Q9N/pitaLolQ/pewm4YjqUA8rGC3OkyL06huz+Ow382TvMDVLk0nctMvCrg1h
+IJFlCD5I8xhcIAqp7wzEHVHQ9jRT9NjElG+PF6FwGi6IW3A8wL8fGru2N84OeJbs
+ROrn33HqVsoqZUdXSPG5YGxM7c7wfUBx3g1/Ou3gxLlqp4a/kX0=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbegAwIBAgIDDeS0MA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwFzEVMBMGA1UEAxMMaW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2v+yrEqrNHOD30WnfdjgDQx+bWF46/zUArFU
+aeHSzjKEaZcSXI4a3vtFS5NH7AGE8kcrOWRSpgG9WC1CSSW9doHqz0eVK/vBDa62
+J3eZPh0kc2pgrwPRWZjzoQLpaApIq1j7xskp5PC21GA3mDKQCI/Z/TpuBoD38jwR
+TzmJOA4/+0zf+5dH4qyzHtE+K/WrUdNnonZ9ohK9WAlDhKAZ8N4VFb75VQJOYhdK
+sBiqQqBiw1Wg9IRSCeDSq3O6zjDznzQAa0hmKanqq+VVwgq8z9GRCXa3y2RawnU6
+oVfRKTQnRqUxtRobjXUCArDatsZ4xr1A4fDMCPcLyaEMOCG7CQIDAQABoxMwETAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQClkXYt95OajuH5Xqut
+KO52XMAeJSC+lAp7sT32tUAZgsV0x5YEAKbo6W9hWuSPdx99r9bPgfQ0sqc1gRgS
+wyW3ZbB/rNrQqQqNYzBWwKrg3uTCGA1o85SqX8aiDJuygBySllTzGztENTApWYwN
+LJATS9yPgn/31BHyfZ29v+6fa3cnuRitVGIW/thDwz8IPqPSNqGTO8Obf/6WDOK/
+7pkji2rHG25Gi/3mWOvnjejbKwb4w4ZlihcNc60ra+0qEM5xstGz6dMJ3sd/w/Fq
+7d/4qhAEpJ7GPg/A5eVGyTYhpYuBA68KoQrrPf2CCGUFQxLQm6UQlICB5AREWOmi
+hZGG
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa2gAwIBAgIDAIddMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMTB1Rl
+c3QgQ2EwKhgTMjAxNTAxMDEwMDAwMDArMDAwMBgTMjAyNTAxMDEwMDAwMDArMDAw
+MDAXMRUwEwYDVQQDEwxpbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDa/7KsSqs0c4PfRad92OANDH5tYXjr/NQCsVRp4dLOMoRplxJc
+jhre+0VLk0fsAYTyRys5ZFKmAb1YLUJJJb12gerPR5Ur+8ENrrYnd5k+HSRzamCv
+A9FZmPOhAuloCkirWPvGySnk8LbUYDeYMpAIj9n9Om4GgPfyPBFPOYk4Dj/7TN/7
+l0firLMe0T4r9atR02eidn2iEr1YCUOEoBnw3hUVvvlVAk5iF0qwGKpCoGLDVaD0
+hFIJ4NKrc7rOMPOfNABrSGYpqeqr5VXCCrzP0ZEJdrfLZFrCdTqhV9EpNCdGpTG1
+GhuNdQICsNq2xnjGvUDh8MwI9wvJoQw4IbsJAgMBAAGjEzARMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJnqAkMbjA4+FFLAapxM+MMLjIVmtSB7
+je7U8APLI0jeY/Wye/OAsOI2vmn7PYVsCTQXr14sCJz863UHrrlDF8ejf0nqSfUM
+bSXvc23XuDmcDqoM2UroHqRmZa0SC1cFC6aJ5ODwioB98cSiPzr24aWcr43dtO4P
+OOjmDXzpC7E67amn3luUIpDJ8epHPIT8+hxP2FP7CHlYUxKQFh3l/t3ftlVF9QId
+992TbF9dDluhzWVh7jsNRJrq2cEIPn6dBsPRPncOcvYton4nvpmDaeS9/d5ktkij
+LCpJv0ECxC/kcPQu65twBWhPwER/hOV0Tq9VYVDpgP3k/K4YdXs1UhY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC1DCCAbygAwIBAgIDDYaqMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwHDEaMBgGA1UEAxMRYmxhY2tsaXN0IHRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDafYp6+Gs5ZjfLfU2EH/NYpvdBUyPz
+veQBJCE4PhBYhOm+Z+J6aX0rSHqU4VTJ8H0TOb6Fh54zBUkIQJHx8YTIsXVmDj0O
+louWAa3uYpIOeBz46knJxdTI9NG6XnsHMYUICZPM8CHtHhoaYnhaRFTcGIg+Y9Hl
+BxMTYXXtqjicg10YuSuEkwMuDT7CbmnmYon8Gt5+ygHIe8YFWdCicpzm5wlPvRu4
+D+WiH2mTgfFG5D5QDoRnxnHWAcO8/+UenFtnbfRip9h6TrzXoJSHtuYW3rMCDVG3
+owVwUE3+ExMcbWKn+qaqGQsjrLlwyYEcKjhH67iPFcTtvZfCsgv8YG75AgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAILNS2XgO4Qa
+plyF7wbQFvVlFFe1QIiEiPZcopqb0zEse73IPBGUnoIt3C9keCv8Q6d7h0x2fe2N
+IqD4P9WXGQYiobBnTci1d2nW5dBq1WVDcpK4cNVsDX7SBE6sd19JEAazNSPIQJ6T
+sts2JXXdTssAyVqGAnq6TwQ2U5ArzuC5pCmr7FcfYAH0sCZM5VWw+ffJylDMBfeG
+oWyjH6f+TmkDd7yvIDh+ptn7Qv+LRxIjHDLPOxG9Y6JaDYtVqKJWh7er5/HFlwUi
+E6gpIuFM6It5ogUtmik2B19bPWpcnGFhv01IKBgmihpzd8LyCmxTtkK11KMxS1JF
+xZSCP3mJTbQ=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICwDCCAaigAwIBAgIDBWa1MA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMTB1Rl
+c3QgQ2EwKhgTMjAxNTAxMDEwMDAwMDArMDAwMBgTMjAyNTAxMDEwMDAwMDArMDAw
+MDASMRAwDgYDVQQDEwdUZXN0IENhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAuk5Hq/uHOz7E3gEZFXKb0ZFslODflO7vB/VT3dmHyGXxuDK5fgQB4xPz
+uoU1VSpD9Pxpe9u+6jNlShEZ5xN34c2F6g+stU4lUS5udqCZVEtB6/etOOpMuiWU
+Ud2DVkEAn9weWkJmKy2gkLQ8p2Iw+0mPlhKKFI9brhGTEpQDTvW9sbLmSQFSEk30
+Ia5rxii/cgu8j5AQmsvUQA06vHXq6/xIsQIj1UFMycBmPz8BvrVO/c891vD9f2Uq
+gQg4p084rmsc6a7PAhBibTOFs3m91HNyZuY2M3pA1r1oLPRQ3WYXb8Wt+kHVtKAr
+L6qDXtofCU3RGhAruwjmuOWftgNsGwIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/
+MA0GCSqGSIb3DQEBCwUAA4IBAQCkFKi9HmsOyn4Wh6RpzwSh39L6e48IdOMcNpOK
+O38tO2rO/uNnhGn2ptnUJkwYS7XOy/A09q1iZNbiuwBweIxc8Z17vpNmk7cF4TMw
+lMRJjDE3Dm2qjTs/lDOknGuzB38Q8tGN/ZbYUHjjf4TZHk5FXCzRUUp+UMzxlOuc
+HAuNuBlQUW88s26h7NdNr115VCbouAI7YkWJRmS2FbeQD5Nwx/kZcvLtJyKasx+n
+imeqy3kCW1NzP9nwlsx2vwW6ydGsdHxqsfrRpdRSLHjzQDA+5m5xMNV0oTr86Iex
+mkqHtIMbOOUpzrE3PACA4m7IgA6AcSkV5gGM9AgqcYccC3St
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/res/raw/fuzz.webm b/tests/tests/security/res/raw/fuzz.webm
new file mode 100755
index 0000000..e5d95ce
--- /dev/null
+++ b/tests/tests/security/res/raw/fuzz.webm
Binary files differ
diff --git a/tests/tests/security/res/raw/test_blacklist_ca.pem b/tests/tests/security/res/raw/test_blacklist_ca.pem
new file mode 100644
index 0000000..b087d56
--- /dev/null
+++ b/tests/tests/security/res/raw/test_blacklist_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC1DCCAbygAwIBAgIDDYaqMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwHDEaMBgGA1UEAxMRYmxhY2tsaXN0IHRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDafYp6+Gs5ZjfLfU2EH/NYpvdBUyPz
+veQBJCE4PhBYhOm+Z+J6aX0rSHqU4VTJ8H0TOb6Fh54zBUkIQJHx8YTIsXVmDj0O
+louWAa3uYpIOeBz46knJxdTI9NG6XnsHMYUICZPM8CHtHhoaYnhaRFTcGIg+Y9Hl
+BxMTYXXtqjicg10YuSuEkwMuDT7CbmnmYon8Gt5+ygHIe8YFWdCicpzm5wlPvRu4
+D+WiH2mTgfFG5D5QDoRnxnHWAcO8/+UenFtnbfRip9h6TrzXoJSHtuYW3rMCDVG3
+owVwUE3+ExMcbWKn+qaqGQsjrLlwyYEcKjhH67iPFcTtvZfCsgv8YG75AgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAILNS2XgO4Qa
+plyF7wbQFvVlFFe1QIiEiPZcopqb0zEse73IPBGUnoIt3C9keCv8Q6d7h0x2fe2N
+IqD4P9WXGQYiobBnTci1d2nW5dBq1WVDcpK4cNVsDX7SBE6sd19JEAazNSPIQJ6T
+sts2JXXdTssAyVqGAnq6TwQ2U5ArzuC5pCmr7FcfYAH0sCZM5VWw+ffJylDMBfeG
+oWyjH6f+TmkDd7yvIDh+ptn7Qv+LRxIjHDLPOxG9Y6JaDYtVqKJWh7er5/HFlwUi
+E6gpIuFM6It5ogUtmik2B19bPWpcnGFhv01IKBgmihpzd8LyCmxTtkK11KMxS1JF
+xZSCP3mJTbQ=
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/src/android/security/cts/CertBlacklistTest.java b/tests/tests/security/src/android/security/cts/CertBlacklistTest.java
new file mode 100644
index 0000000..d7a199e
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CertBlacklistTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.security.cts;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * End to end version of org.conscrypt.CertBlacklistTest that tests the platform default
+ * {@link X509TrustManager}.
+ *
+ * The test blacklisted CA's private key can be found in
+ * external/conscrypt/src/test/resources/blacklist_ca_key.pem
+ */
+public class CertBlacklistTest extends AndroidTestCase {
+
+    private static final int BLACKLIST_CA = R.raw.test_blacklist_ca;
+    private static final int BLACKLISTED_CHAIN = R.raw.blacklist_test_chain;
+    private static final int BLACKLIST_FALLBACK_VALID_CA = R.raw.blacklist_test_valid_ca;
+    private static final int BLACKLISTED_VALID_CHAIN = R.raw.blacklist_test_valid_chain;
+
+    /**
+     * Checks that the blacklisted CA is rejected even if it used as a root of trust
+     */
+    public void testBlacklistedCaUntrusted() throws Exception {
+        X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+        assertUntrusted(new X509Certificate[] {blacklistedCa}, getTrustManager(blacklistedCa));
+    }
+
+    /**
+     * Checks that a chain that is rooted in a blacklisted trusted CA is rejected.
+     */
+    public void testBlacklistedRootOfTrust() throws Exception {
+        // Chain is leaf -> blacklisted
+        X509Certificate[] chain = loadCertificates(BLACKLISTED_CHAIN);
+        X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+        assertUntrusted(chain, getTrustManager(blacklistedCa));
+    }
+
+    /**
+     * Tests that the path building correctly routes around a blacklisted cert where there are
+     * other valid paths available. This prevents breakage where a cert was cross signed by a
+     * blacklisted CA but is still valid due to also being cross signed by CAs that remain trusted.
+     * Path:
+     *
+     * leaf -> intermediate -> blacklisted_ca
+     *               \
+     *                -------> trusted_ca
+     */
+    public void testBlacklistedIntermediateFallback() throws Exception {
+        X509Certificate[] chain = loadCertificates(BLACKLISTED_VALID_CHAIN);
+        X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+        X509Certificate validCa = loadCertificate(BLACKLIST_FALLBACK_VALID_CA);
+        assertTrusted(chain, getTrustManager(blacklistedCa, validCa));
+        // Check that without the trusted_ca the chain is invalid (since it only chains to a
+        // blacklisted ca)
+        assertUntrusted(chain, getTrustManager(blacklistedCa));
+    }
+
+    private X509Certificate loadCertificate(int resId) throws Exception {
+        return loadCertificates(resId)[0];
+    }
+
+    private X509Certificate[] loadCertificates(int resId) throws Exception {
+        CertificateFactory factory = CertificateFactory.getInstance("X.509");
+        try (InputStream is = getContext().getResources().openRawResource(resId)) {
+            Collection<? extends Certificate> collection = factory.generateCertificates(is);
+            X509Certificate[] certs = new X509Certificate[collection.size()];
+            int i = 0;
+            for (Certificate cert : collection) {
+                certs[i++] = (X509Certificate) cert;
+            }
+            return certs;
+        }
+    }
+
+    private static X509TrustManager getTrustManager(X509Certificate... trustedCas)
+            throws Exception {
+        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+        ks.load(null);
+        int i = 0;
+        for (X509Certificate ca : trustedCas) {
+            ks.setCertificateEntry(String.valueOf(i++), ca);
+        }
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(ks);
+        for (TrustManager tm : tmf.getTrustManagers()) {
+            if (tm instanceof X509TrustManager) {
+                return (X509TrustManager) tm;
+            }
+        }
+        fail("Could not find default X509TrustManager");
+        return null;
+    }
+
+    private static void assertTrusted(X509Certificate[] certs, X509TrustManager tm)
+            throws Exception {
+        tm.checkServerTrusted(certs, "RSA");
+    }
+
+    private static void assertUntrusted(X509Certificate[] certs, X509TrustManager tm) {
+        try {
+            tm.checkServerTrusted(certs, "RSA");
+            fail();
+        } catch (CertificateException expected) {
+        }
+    }
+}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/security/src/android/security/cts/DisplayDriverActivity.java
old mode 100644
new mode 100755
similarity index 81%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/security/src/android/security/cts/DisplayDriverActivity.java
index 481f5be..ca6c898
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/security/src/android/security/cts/DisplayDriverActivity.java
@@ -1,30 +1,30 @@
-/*
- * 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.server.app;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class SlowCreateActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
-        super.onCreate(savedInstanceState);
-    }
-}
+/*

+ * 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.security.cts;

+

+import android.security.cts.R;

+

+import android.app.Activity;

+import android.os.Bundle;

+

+public class DisplayDriverActivity extends Activity {

+    @Override

+    protected void onCreate(Bundle savedInstanceState) {

+        super.onCreate(savedInstanceState);

+        setContentView(R.layout.activity_displaydriver);

+    }

+}

diff --git a/tests/tests/security/src/android/security/cts/DisplayDriverTest.java b/tests/tests/security/src/android/security/cts/DisplayDriverTest.java
new file mode 100755
index 0000000..7f3a0d4
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/DisplayDriverTest.java
@@ -0,0 +1,115 @@
+/*

+ * 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.security.cts;

+

+import android.security.cts.R;

+

+import android.app.Activity;

+import android.media.MediaPlayer;

+import android.media.MediaPlayer.OnErrorListener;

+import android.net.Uri;

+import android.os.SystemClock;

+import android.test.ActivityInstrumentationTestCase2;

+import android.widget.MediaController;

+import android.widget.VideoView;

+

+public class DisplayDriverTest extends

+        ActivityInstrumentationTestCase2<DisplayDriverActivity> {

+    /**

+     * The maximum time to wait for an operation.

+     */

+    private static final int TIMEOUT_ASYNC_PROCESSING = 3000;

+    private Activity mActivity;

+

+    public DisplayDriverTest() {

+        super(DisplayDriverActivity.class);

+    }

+

+    /**

+     * Checks whether video crashed or not

+     * 1. Initializes mTriggered to false

+     * 2. sets mTriggered to true if onError() occurred while playing video

+     */

+    private static class MockListener {

+        private boolean mTriggered;

+

+        MockListener() {

+            mTriggered = false;

+        }

+

+        public boolean isTriggered() {

+            return mTriggered;

+        }

+

+        protected void onEvent() {

+            mTriggered = true;

+        }

+    }

+

+    private static class MockOnErrorListener extends MockListener implements

+            OnErrorListener {

+        public boolean onError(MediaPlayer mp, int what, int extra) {

+            super.onEvent();

+            return false;

+        }

+    }

+

+    @Override

+    protected void setUp() throws Exception {

+        super.setUp();

+        mActivity = getActivity();

+        assertNotNull("Failed to get the activity instance", mActivity);

+    }

+

+    /**

+     * 1. Runs the vulnerable video by registering OnErrorListener for VideoView

+     * 2. Wait for max time taken by video to crash and hit OnErrorListener

+     * 3. if video crashed - Pass the test case otherwise Fail the test case

+     */

+    public void testDisplayDriver_cve_2015_6634() {

+        final MockOnErrorListener listener = new MockOnErrorListener();

+        mActivity.runOnUiThread(new Runnable() {

+            @Override

+            public void run() {

+                try {

+                    MediaController mMediaControls =

+                            new MediaController(mActivity);

+                    VideoView mVideoView =

+                            (VideoView) mActivity.findViewById(R.id.videoview);

+                    mVideoView.setMediaController(mMediaControls);

+                    mVideoView.setOnErrorListener(listener);

+                    mVideoView.setVideoURI(Uri.parse("android.resource://" +

+                            mActivity.getPackageName() + "/" + R.raw.fuzz));

+                    mVideoView.start();

+                } catch (Exception e) {

+                    listener.onError(null, 0, 0);

+                }

+            }

+        });

+        SystemClock.sleep(TIMEOUT_ASYNC_PROCESSING);

+        assertTrue("Test case failed due to vulnerability in the video: " +

+                        "Device is vulenrable to CVE-2015-6634", listener.isTriggered());

+    }

+

+    @Override

+    protected void tearDown() throws Exception {

+        if (mActivity != null) {

+            mActivity.finish();

+        }

+        super.tearDown();

+    }

+}

diff --git a/tests/tests/speech/Android.mk b/tests/tests/speech/Android.mk
index 3d95053..68e0cba 100755
--- a/tests/tests/speech/Android.mk
+++ b/tests/tests/speech/Android.mk
@@ -21,7 +21,7 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/systemui/Android.mk b/tests/tests/systemui/Android.mk
index 536d2a8..c31d825 100644
--- a/tests/tests/systemui/Android.mk
+++ b/tests/tests/systemui/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/telecom/Android.mk b/tests/tests/telecom/Android.mk
index 5a8922e..27947af 100644
--- a/tests/tests/telecom/Android.mk
+++ b/tests/tests/telecom/Android.mk
@@ -24,7 +24,7 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java b/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java
index 0f09314..b15a4e8 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java
@@ -265,4 +265,20 @@
         } catch (SecurityException expected) {
         }
     }
+
+    /**
+     * Tests the TelephonyManager.getIccAuthentication() API. This makes a call to
+     * getIccAuthentication() API and expects a SecurityException since the test apk is not
+     * signed by certificate on the SIM.
+     */
+    public void testGetIccAuthentication() {
+        try {
+            if (isSimCardPresent()) {
+                TelephonyManager.getDefault().getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+                        TelephonyManager.AUTHTYPE_EAP_AKA, "");
+                fail("Expected SecurityException. App doesn't have carrier privileges.");
+            }
+        } catch (SecurityException expected) {
+        }
+    }
 }
diff --git a/tests/tests/text/Android.mk b/tests/tests/text/Android.mk
index 65a93fb..fbc7a59 100644
--- a/tests/tests/text/Android.mk
+++ b/tests/tests/text/Android.mk
@@ -23,7 +23,12 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctsdeviceutillegacy ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES += \
+    ctsdeviceutil \
+    ctsdeviceutillegacy \
+    ctstestrunner \
+    android-support-test \
+    mockito-target \
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/text/AndroidManifest.xml b/tests/tests/text/AndroidManifest.xml
index fea237f..40a0b50 100644
--- a/tests/tests/text/AndroidManifest.xml
+++ b/tests/tests/text/AndroidManifest.xml
@@ -68,7 +68,7 @@
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.BROWSABLE" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-                <data android:scheme="ctstest" />
+                <data android:scheme="ctstesttext" />
             </intent-filter>
         </activity>
 
diff --git a/tests/tests/text/res/values/strings.xml b/tests/tests/text/res/values/strings.xml
index c167278..b3db2a6 100644
--- a/tests/tests/text/res/values/strings.xml
+++ b/tests/tests/text/res/values/strings.xml
@@ -165,7 +165,7 @@
    <string name="themes_prompt">Select a Theme:</string>
    <string name="sample_text">Sample text goes here. I wanted something creative and whimsical
 but then I just got bored...</string>
-    <string name="long_text">This is a really long string which exceeds the width of the view.
+   <string name="long_text">This is a really long string which exceeds the width of the view.
 New devices have a much larger screen which actually enables long strings to be displayed
 with no fading. I have made this string longer to fix this case. If you are correcting this
 text, I would love to see the kind of devices you guys now use! Guys, maybe some devices need longer string!
@@ -176,4 +176,8 @@
 text, I would love to see the kind of devices you guys now use! Guys, maybe some devices need longer string!
 I think so, so how about double this string, like copy and paste! </string>
     <string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
+    <plurals name="list_ellipsize_test">
+        <item quantity="one">one more</item>
+        <item quantity="other"><xliff:g id="number">%d</xliff:g> more</item>
+    </plurals>
 </resources>
diff --git a/tests/tests/text/src/android/text/cts/AutoTextTest.java b/tests/tests/text/src/android/text/cts/AutoTextTest.java
index cbea4d9..867b34e 100644
--- a/tests/tests/text/src/android/text/cts/AutoTextTest.java
+++ b/tests/tests/text/src/android/text/cts/AutoTextTest.java
@@ -16,11 +16,12 @@
 
 package android.text.cts;
 
-import java.util.Locale;
+import android.content.res.Configuration;
 import android.test.AndroidTestCase;
 import android.text.AutoText;
 import android.view.View;
-import android.content.res.Configuration;
+
+import java.util.Locale;
 
 public class AutoTextTest extends AndroidTestCase {
 
diff --git a/tests/tests/text/src/android/text/cts/BidiFormatterTest.java b/tests/tests/text/src/android/text/cts/BidiFormatterTest.java
index 3e5db4d..b7aec1b 100644
--- a/tests/tests/text/src/android/text/cts/BidiFormatterTest.java
+++ b/tests/tests/text/src/android/text/cts/BidiFormatterTest.java
@@ -16,9 +16,13 @@
 
 package android.text.cts;
 
+import android.icu.util.ULocale;
 import android.test.AndroidTestCase;
 import android.text.BidiFormatter;
+import android.text.SpannableString;
+import android.text.Spanned;
 import android.text.TextDirectionHeuristics;
+import android.text.style.RelativeSizeSpan;
 
 import java.util.Locale;
 
@@ -233,4 +237,83 @@
                 LRE + HE + EN + HE + PDF,
                 RTL_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristics.LTR, false));
     }
+
+    public void testGetStereoReset() {
+        assertTrue(LTR_FMT.getStereoReset());
+        assertTrue(RTL_FMT.getStereoReset());
+        assertFalse(LTR_FMT_EXIT_RESET.getStereoReset());
+        assertFalse(RTL_FMT_EXIT_RESET.getStereoReset());
+    }
+
+    public void testBuilder_construction() {
+        final BidiFormatter defaultFmt = new BidiFormatter.Builder().build();
+        // Test that the default locale and the BidiFormatter's locale have the same direction.
+        assertEquals(ULocale.getDefault().isRightToLeft(), defaultFmt.isRtlContext());
+
+        final BidiFormatter ltrFmt = new BidiFormatter.Builder(false).build();
+        assertFalse(ltrFmt.isRtlContext());
+
+        final BidiFormatter rtlFmt = new BidiFormatter.Builder(true).build();
+        assertTrue(rtlFmt.isRtlContext());
+
+        final BidiFormatter englishFmt = new BidiFormatter.Builder(Locale.ENGLISH).build();
+        assertFalse(englishFmt.isRtlContext());
+
+        final BidiFormatter arabicFmt =
+                new BidiFormatter.Builder(Locale.forLanguageTag("ar")).build();
+        assertTrue(arabicFmt.isRtlContext());
+    }
+
+    public void testBuilder_setTextDirectionHeuristic() {
+        final BidiFormatter defaultFmt = new BidiFormatter.Builder().build();
+        assertFalse(defaultFmt.isRtl(EN + HE + EN));
+
+        final BidiFormatter modifiedFmt = new BidiFormatter.Builder().setTextDirectionHeuristic(
+                TextDirectionHeuristics.ANYRTL_LTR).build();
+        assertTrue(modifiedFmt.isRtl(EN + HE + EN));
+    }
+
+    public void testCharSequenceApis() {
+        final CharSequence CS_HE = new SpannableString(HE);
+        assertEquals(true, BidiFormatter.getInstance(true).isRtl(CS_HE));
+
+        final SpannableString CS_EN_HE = new SpannableString(EN + HE);
+        final Object RELATIVE_SIZE_SPAN = new RelativeSizeSpan(1.2f);
+        CS_EN_HE.setSpan(RELATIVE_SIZE_SPAN, 0, EN.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+        Spanned wrapped;
+        Object[] spans;
+
+        wrapped = (Spanned) LTR_FMT.unicodeWrap(CS_EN_HE);
+        assertEquals(EN + HE + LRM, wrapped.toString());
+        spans = wrapped.getSpans(0, wrapped.length(), Object.class);
+        assertEquals(1, spans.length);
+        assertEquals(RELATIVE_SIZE_SPAN, spans[0]);
+        assertEquals(0, wrapped.getSpanStart(RELATIVE_SIZE_SPAN));
+        assertEquals(EN.length(), wrapped.getSpanEnd(RELATIVE_SIZE_SPAN));
+
+        wrapped = (Spanned) LTR_FMT.unicodeWrap(CS_EN_HE, TextDirectionHeuristics.LTR);
+        assertEquals(EN + HE + LRM, wrapped.toString());
+        spans = wrapped.getSpans(0, wrapped.length(), Object.class);
+        assertEquals(1, spans.length);
+        assertEquals(RELATIVE_SIZE_SPAN, spans[0]);
+        assertEquals(0, wrapped.getSpanStart(RELATIVE_SIZE_SPAN));
+        assertEquals(EN.length(), wrapped.getSpanEnd(RELATIVE_SIZE_SPAN));
+
+        wrapped = (Spanned) LTR_FMT.unicodeWrap(CS_EN_HE, false);
+        assertEquals(EN + HE, wrapped.toString());
+        spans = wrapped.getSpans(0, wrapped.length(), Object.class);
+        assertEquals(1, spans.length);
+        assertEquals(RELATIVE_SIZE_SPAN, spans[0]);
+        assertEquals(0, wrapped.getSpanStart(RELATIVE_SIZE_SPAN));
+        assertEquals(EN.length(), wrapped.getSpanEnd(RELATIVE_SIZE_SPAN));
+
+        wrapped = (Spanned) LTR_FMT.unicodeWrap(CS_EN_HE, TextDirectionHeuristics.LTR, false);
+        assertEquals(EN + HE, wrapped.toString());
+        spans = wrapped.getSpans(0, wrapped.length(), Object.class);
+        assertEquals(1, spans.length);
+        assertEquals(RELATIVE_SIZE_SPAN, spans[0]);
+        assertEquals(0, wrapped.getSpanStart(RELATIVE_SIZE_SPAN));
+        assertEquals(EN.length(), wrapped.getSpanEnd(RELATIVE_SIZE_SPAN));
+    }
 }
diff --git a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
index 13465ae..d181d01 100644
--- a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
@@ -16,17 +16,22 @@
 
 package android.text.cts;
 
+import static android.cts.util.WidgetTestUtils.sameCharSequence;
+
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.graphics.Bitmap.Config;
 import android.test.AndroidTestCase;
 import android.text.BoringLayout;
 import android.text.BoringLayout.Metrics;
 import android.text.Layout;
+import android.text.Layout.Alignment;
 import android.text.TextPaint;
 import android.text.TextUtils;
-import android.text.Layout.Alignment;
 
 public class BoringLayoutTest extends AndroidTestCase {
     private static final float SPACING_MULT_NO_SCALE = 1.0f;
@@ -282,7 +287,7 @@
     }
 
     public void testDraw() {
-        BoringLayout boringLayout = BoringLayout.make((String)DEFAULT_CHAR_SEQUENCE,
+        BoringLayout boringLayout = BoringLayout.make(DEFAULT_CHAR_SEQUENCE,
                 DEFAULT_PAINT,
                 DEFAULT_OUTER_WIDTH,
                 Alignment.ALIGN_NORMAL,
@@ -291,24 +296,24 @@
                 DEFAULT_METRICS,
                 true);
 
-        Bitmap mMutableBitmap = Bitmap.createBitmap(10, 28, Config.ARGB_8888);
-        MockCanvas c = new MockCanvas(mMutableBitmap);
-        boringLayout.draw(c, null, null, 0);
-        assertTrue(c.isCanvasCalling);
-    }
+        Bitmap mutableBitmap = Bitmap.createBitmap(10, 28, Config.ARGB_8888);
+        Canvas canvas = spy(new Canvas(mutableBitmap));
+        boringLayout.draw(canvas, null, null, 0);
+        verify(canvas, times(1)).drawText(eq(DEFAULT_CHAR_SEQUENCE.toString()),
+                anyFloat(), anyFloat(), any(Paint.class));
 
-    private class MockCanvas extends Canvas {
-        public boolean isCanvasCalling = false;
-
-        public MockCanvas(Bitmap bitmap) {
-            super(bitmap);
-        }
-
-        @Override
-        public void drawText(String text, float x, float y, Paint paint) {
-            super.drawText(text, x, y, paint);
-            isCanvasCalling = true;
-        }
+        reset(canvas);
+        boringLayout = BoringLayout.make(DEFAULT_CHAR_SEQUENCE,
+                DEFAULT_PAINT,
+                DEFAULT_OUTER_WIDTH,
+                Alignment.ALIGN_OPPOSITE,
+                SPACING_MULT_NO_SCALE,
+                SPACING_ADD_NO_SCALE,
+                DEFAULT_METRICS,
+                true);
+        boringLayout.draw(canvas, null, null, 0);
+        verify(canvas, times(1)).drawText(sameCharSequence(DEFAULT_CHAR_SEQUENCE),
+                anyInt(), anyInt(), anyFloat(), anyFloat(), any(Paint.class));
     }
 
     private static Metrics createMetrics(
diff --git a/tests/tests/text/src/android/text/cts/Editable_FactoryTest.java b/tests/tests/text/src/android/text/cts/Editable_FactoryTest.java
index 8dde216..815f5eb 100644
--- a/tests/tests/text/src/android/text/cts/Editable_FactoryTest.java
+++ b/tests/tests/text/src/android/text/cts/Editable_FactoryTest.java
@@ -18,8 +18,8 @@
 
 import android.test.AndroidTestCase;
 import android.text.Editable;
-import android.text.SpannableStringBuilder;
 import android.text.Editable.Factory;
+import android.text.SpannableStringBuilder;
 
 public class Editable_FactoryTest extends AndroidTestCase {
 
diff --git a/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java b/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java
index cdbc867..fa7e2b8 100644
--- a/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java
+++ b/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java
@@ -16,11 +16,10 @@
 
 package android.text.cts;
 
-import android.text.cts.R;
-
 import android.app.Activity;
-import android.os.Bundle;
 import android.cts.util.NullWebViewUtils;
+import android.os.Bundle;
+import android.text.cts.R;
 import android.webkit.WebView;
 
 public class EmojiCtsActivity extends Activity {
diff --git a/tests/tests/text/src/android/text/cts/EmojiTest.java b/tests/tests/text/src/android/text/cts/EmojiTest.java
index 4bc586e..b67f8c9 100644
--- a/tests/tests/text/src/android/text/cts/EmojiTest.java
+++ b/tests/tests/text/src/android/text/cts/EmojiTest.java
@@ -25,11 +25,10 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.TypedValue;
 import android.view.KeyEvent;
-import android.view.Menu;
 import android.view.View;
-import android.widget.TextView;
-import android.widget.EditText;
 import android.webkit.cts.WebViewOnUiThread;
+import android.widget.EditText;
+import android.widget.TextView;
 
 public class EmojiTest extends ActivityInstrumentationTestCase2<EmojiCtsActivity> {
 
@@ -155,13 +154,9 @@
             newStr = editText.getText().toString();
             assertEquals(newStr.codePointCount(0, newStr.length()), origStr.length() + 1);
 
-            runTestOnUiThread(new Runnable() {
-                public void run() {
-                    // Delete added character by sending KEYCODE_DEL event
-                    editText.dispatchKeyEvent(
-                            new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
-                }
-            });
+            // Delete added character by sending KEYCODE_DEL event
+            runTestOnUiThread(() -> editText.dispatchKeyEvent(
+                    new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)));
             getInstrumentation().waitForIdleSync();
 
             newStr = editText.getText().toString();
diff --git a/tests/tests/text/src/android/text/cts/GetCharsTest.java b/tests/tests/text/src/android/text/cts/GetCharsTest.java
new file mode 100644
index 0000000..41e7ccc
--- /dev/null
+++ b/tests/tests/text/src/android/text/cts/GetCharsTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.text.cts;
+
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+import android.text.GetChars;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.SpannedString;
+
+public class GetCharsTest extends AndroidTestCase {
+
+    // Returns an array of three GetChars objects, of three different classes:
+    // SpannableString, SpannableStringBuilder, and SpannedString.
+    private static GetChars[] makeGetChars(String s) {
+        return new GetChars[]{
+                new SpannableString(s),
+                new SpannableStringBuilder(s),
+                new SpannedString(s)};
+    }
+
+    @SmallTest
+    public void testGetChars() {
+        final GetChars[] getCharsCases = makeGetChars("\uD83D\uDE00");  // U+1F600 GRINNING FACE
+        for (GetChars getChars : getCharsCases) {
+            final char[] target = new char[getChars.length()];
+            getChars.getChars(0, getChars.length(), target, 0);
+            assertEquals('\uD83D', target[0]);
+            assertEquals('\uDE00', target[1]);
+
+            try {
+                getChars.getChars(-1, getChars.length(), target, 0);
+                fail("should throw IndexOutOfBoundsException here");
+            } catch (IndexOutOfBoundsException e) {
+            }
+
+            try {
+                getChars.getChars(1, 0, target, 0);
+                fail("should throw IndexOutOfBoundsException here");
+            } catch (IndexOutOfBoundsException e) {
+            }
+
+            try {
+                getChars.getChars(0, getChars.length() + 1, target, 0);
+                fail("should throw IndexOutOfBoundsException here");
+            } catch (IndexOutOfBoundsException e) {
+            }
+
+            try {
+                getChars.getChars(0, getChars.length(), target, -1);
+                fail("should throw IndexOutOfBoundsException here");
+            } catch (IndexOutOfBoundsException e) {
+            }
+
+            try {
+                getChars.getChars(0, getChars.length(), target, 1);
+                fail("should throw IndexOutOfBoundsException here");
+            } catch (IndexOutOfBoundsException e) {
+            }
+        }
+    }
+}
+
+
diff --git a/tests/tests/text/src/android/text/cts/HtmlTest.java b/tests/tests/text/src/android/text/cts/HtmlTest.java
index ad4d2aa..076d0a4 100644
--- a/tests/tests/text/src/android/text/cts/HtmlTest.java
+++ b/tests/tests/text/src/android/text/cts/HtmlTest.java
@@ -17,8 +17,6 @@
 package android.text.cts;
 
 import static org.hamcrest.MatcherAssert.assertThat;
-import org.hamcrest.Description;
-import org.hamcrest.BaseMatcher;
 
 import android.graphics.Typeface;
 import android.test.AndroidTestCase;
@@ -27,8 +25,6 @@
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.Spanned;
-import android.text.Html.ImageGetter;
-import android.text.Html.TagHandler;
 import android.text.style.AlignmentSpan;
 import android.text.style.BackgroundColorSpan;
 import android.text.style.BulletSpan;
@@ -42,6 +38,9 @@
 import android.text.style.URLSpan;
 import android.text.style.UnderlineSpan;
 
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+
 public class HtmlTest extends AndroidTestCase {
     private final static int SPAN_EXCLUSIVE_INCLUSIVE = Spannable.SPAN_EXCLUSIVE_INCLUSIVE;
 
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 2eec7d7..93ee064 100644
--- a/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
+++ b/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
@@ -18,8 +18,8 @@
 
 import android.test.AndroidTestCase;
 import android.text.InputFilter;
-import android.text.SpannableStringBuilder;
 import android.text.InputFilter.AllCaps;
+import android.text.SpannableStringBuilder;
 
 public class InputFilter_AllCapsTest extends AndroidTestCase {
 
diff --git a/tests/tests/text/src/android/text/cts/InputFilter_LengthFilterTest.java b/tests/tests/text/src/android/text/cts/InputFilter_LengthFilterTest.java
index db06ef6..49006df 100644
--- a/tests/tests/text/src/android/text/cts/InputFilter_LengthFilterTest.java
+++ b/tests/tests/text/src/android/text/cts/InputFilter_LengthFilterTest.java
@@ -18,8 +18,8 @@
 
 import android.test.AndroidTestCase;
 import android.text.InputFilter;
-import android.text.SpannableStringBuilder;
 import android.text.InputFilter.LengthFilter;
+import android.text.SpannableStringBuilder;
 
 public class InputFilter_LengthFilterTest extends AndroidTestCase {
 
@@ -31,6 +31,8 @@
         LengthFilter lengthFilter = new LengthFilter(10);
         InputFilter[] filters = {lengthFilter};
 
+        assertEquals(10, lengthFilter.getMax());
+
         // filter() implicitly invoked. If the total length > filter length, the filter will
         // cut off the source CharSequence from beginning to fit the filter length.
         source = "abc";
diff --git a/tests/tests/text/src/android/text/cts/LayoutTest.java b/tests/tests/text/src/android/text/cts/LayoutTest.java
index 973d883..b8e4bd1 100644
--- a/tests/tests/text/src/android/text/cts/LayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/LayoutTest.java
@@ -17,15 +17,24 @@
 package android.text.cts;
 
 
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
 import android.graphics.Rect;
+import android.graphics.RectF;
+import android.support.test.filters.SmallTest;
 import android.test.AndroidTestCase;
 import android.text.Layout;
+import android.text.Layout.Alignment;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextPaint;
-import android.text.Layout.Alignment;
 import android.text.style.StrikethroughSpan;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class LayoutTest extends AndroidTestCase {
     private final static int LINE_COUNT = 5;
     private final static int LINE_HEIGHT = 12;
@@ -322,7 +331,7 @@
 
         @Override
         public Directions getLineDirections(int line) {
-            return null;
+            return Layout.DIRS_ALL_LEFT_TO_RIGHT;
         }
 
         @Override
@@ -351,4 +360,109 @@
             return 0;
         }
     }
+
+    @SmallTest
+    public void testGetLineWidth() {
+        Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
+                mAlign, mSpacingmult, mSpacingadd);
+        for (int i = 0; i < LINE_COUNT; i++) {
+            int start = layout.getLineStart(i);
+            int end = layout.getLineEnd(i);
+            String text = LAYOUT_TEXT.toString().substring(start, end);
+            assertEquals(mTextPaint.measureText(text), layout.getLineWidth(i), 1.0f);
+        }
+    }
+
+    @SmallTest
+    public void testGetCursorPath() {
+        Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
+                mAlign, mSpacingmult, mSpacingadd);
+        Path path = new Path();
+        final float epsilon = 1.0f;
+        for (int i = 0; i < LINE_COUNT; i++) {
+            layout.getCursorPath(i, path, LAYOUT_TEXT);
+            RectF bounds = new RectF();
+            path.computeBounds(bounds, false);
+            assertTrue(bounds.top >= layout.getLineTop(i) - epsilon);
+            assertTrue(bounds.bottom <= layout.getLineBottom(i) + epsilon);
+        }
+    }
+
+    @SmallTest
+    public void testDraw() {
+        Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
+                mAlign, mSpacingmult, mSpacingadd);
+        final int width = 256;
+        final int height = 256;
+        MockCanvas c = new MockCanvas(width, height);
+        layout.draw(c);
+        List<MockCanvas.DrawCommand> drawCommands = c.getDrawCommands();
+        assertEquals(LINE_COUNT, drawCommands.size());
+        for (int i = 0; i < LINE_COUNT; i++) {
+            MockCanvas.DrawCommand drawCommand = drawCommands.get(i);
+            int start = layout.getLineStart(i);
+            int end = layout.getLineEnd(i);
+            assertEquals(LAYOUT_TEXT.toString().substring(start, end), drawCommand.text);
+            float expected_y = (i + 1) * LINE_HEIGHT - LINE_DESCENT;
+            assertEquals(expected_y, drawCommand.y);
+        }
+    }
+
+    private final class MockCanvas extends Canvas {
+
+        class DrawCommand {
+            final String text;
+            final float x;
+            final float y;
+
+            DrawCommand(String text, float x, float y) {
+                this.text = text;
+                this.x = x;
+                this.y = y;
+            }
+        }
+
+        List<DrawCommand> mDrawCommands;
+
+        public MockCanvas(int width, int height) {
+            super();
+            mDrawCommands = new ArrayList<>();
+            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            setBitmap(bitmap);
+        }
+
+        // Drawing text with either drawText or drawTextRun is valid; we don't care which.
+        // We also don't care which of the string representations is used.
+
+        @Override
+        public void drawText(String text, int start, int end, float x, float y, Paint p) {
+            mDrawCommands.add(new DrawCommand(text.substring(start, end), x, y));
+        }
+
+        @Override
+        public void drawText(CharSequence text, int start, int end, float x, float y, Paint p) {
+            drawText(text.toString(), start, end, x, y, p);
+        }
+
+        @Override
+        public void drawText(char[] text, int index, int count, float x, float y, Paint p) {
+            mDrawCommands.add(new DrawCommand(new String(text, index, count), x, y));
+        }
+
+        @Override
+        public void drawTextRun(CharSequence text, int start, int end, int contextStart,
+                int contextEnd, float x, float y, boolean isRtl, Paint paint) {
+            drawText(text, start, end, x, y, paint);
+        }
+
+        @Override
+        public void drawTextRun(char[] text, int index, int count, int contextIndex,
+                int contextCount, float x, float y, boolean isRtl, Paint paint) {
+            drawText(text, index, count, x, y, paint);
+        }
+
+        List<DrawCommand> getDrawCommands() {
+            return mDrawCommands;
+        }
+    }
 }
diff --git a/tests/tests/text/src/android/text/cts/LoginFilterTest.java b/tests/tests/text/src/android/text/cts/LoginFilterTest.java
index 76f5d04..c968bfa 100644
--- a/tests/tests/text/src/android/text/cts/LoginFilterTest.java
+++ b/tests/tests/text/src/android/text/cts/LoginFilterTest.java
@@ -16,12 +16,17 @@
 
 package android.text.cts;
 
-import junit.framework.TestCase;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
 import android.text.LoginFilter;
+import android.text.LoginFilter.UsernameFilterGeneric;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.SpannedString;
 
+import junit.framework.TestCase;
+
 public class LoginFilterTest extends TestCase {
 
     @Override
@@ -31,57 +36,57 @@
 
     public void testFilter() {
         CharSequence result;
-        MockLoginFilter loginFilter = new MockLoginFilter();
+        LoginFilter loginFilter = spy(new UsernameFilterGeneric());
         Spanned dest1 = new SpannedString("dest_without_invalid_char");
         Spanned dest2 = new SpannedString("&*dest_with_invalid_char#$");
         String source1 = "source_without_invalid_char";
         String source2 = "+=source_with_invalid_char%!";
         Spanned spannedSource = new SpannedString("&*spanned_source_with_invalid_char#$");
 
-        assertFalse(loginFilter.isStarted());
-        assertFalse(loginFilter.isStopped());
-        assertEquals(0, loginFilter.getInvalidCharacterCount());
+        verify(loginFilter, never()).onStart();
+        verify(loginFilter, never()).onStop();
+        verify(loginFilter, never()).onInvalidCharacter(anyChar());
 
         assertNull(loginFilter.filter(source1, 0, source1.length(), dest1, 0, dest1.length()));
-        assertTrue(loginFilter.isStarted());
-        assertTrue(loginFilter.isStopped());
-        assertEquals(0, loginFilter.getInvalidCharacterCount());
+        verify(loginFilter, times(1)).onStart();
+        verify(loginFilter, times(1)).onStop();
+        verify(loginFilter, never()).onInvalidCharacter(anyChar());
 
-        loginFilter.reset();
+        reset(loginFilter);
         assertNull(loginFilter.filter(source1, 0, source1.length(), dest2, 5, 6));
-        assertTrue(loginFilter.isStarted());
-        assertTrue(loginFilter.isStopped());
-        assertEquals(4, loginFilter.getInvalidCharacterCount());
+        verify(loginFilter, times(1)).onStart();
+        verify(loginFilter, times(1)).onStop();
+        verify(loginFilter, times(4)).onInvalidCharacter(anyChar());
 
-        loginFilter = new MockLoginFilter(true);
+        loginFilter = spy(new UsernameFilterGeneric(true));
         assertNull(loginFilter.filter(source2, 0, source2.length(),
                 dest1, 0, dest1.length()));
-        assertTrue(loginFilter.isStarted());
-        assertTrue(loginFilter.isStopped());
-        assertEquals(3, loginFilter.getInvalidCharacterCount());
+        verify(loginFilter, times(1)).onStart();
+        verify(loginFilter, times(1)).onStop();
+        verify(loginFilter, times(3)).onInvalidCharacter(anyChar());
 
-        loginFilter.reset();
+        reset(loginFilter);
         assertNull(loginFilter.filter(spannedSource, 0, spannedSource.length(),
                 dest1, 0, dest1.length()));
-        assertTrue(loginFilter.isStarted());
-        assertTrue(loginFilter.isStopped());
-        assertEquals(4, loginFilter.getInvalidCharacterCount());
+        verify(loginFilter, times(1)).onStart();
+        verify(loginFilter, times(1)).onStop();
+        verify(loginFilter, times(4)).onInvalidCharacter(anyChar());
 
-        loginFilter = new MockLoginFilter(false);
+        loginFilter = spy(new UsernameFilterGeneric(false));
         result = loginFilter.filter(source2, 0, source2.length(), dest1, 0, dest1.length());
         assertFalse(result instanceof SpannableString);
         assertEquals("+source_with_invalid_char", result.toString());
-        assertTrue(loginFilter.isStarted());
-        assertTrue(loginFilter.isStopped());
-        assertEquals(3, loginFilter.getInvalidCharacterCount());
+        verify(loginFilter, times(1)).onStart();
+        verify(loginFilter, times(1)).onStop();
+        verify(loginFilter, times(3)).onInvalidCharacter(anyChar());
 
-        loginFilter.reset();
+        reset(loginFilter);
         result = loginFilter.filter(spannedSource, 0, spannedSource.length(),
                 dest1, 0, dest1.length());
         assertEquals("spanned_source_with_invalid_char", result.toString());
-        assertTrue(loginFilter.isStarted());
-        assertTrue(loginFilter.isStopped());
-        assertEquals(4, loginFilter.getInvalidCharacterCount());
+        verify(loginFilter, times(1)).onStart();
+        verify(loginFilter, times(1)).onStop();
+        verify(loginFilter, times(4)).onInvalidCharacter(anyChar());
 
         try {
             loginFilter.filter(null, 0, source1.length(), dest1, 0, dest1.length());
@@ -117,71 +122,21 @@
     // This method does nothing. we only test onInvalidCharacter function here,
     // the callback should be tested in testFilter()
     public void testOnInvalidCharacter() {
-        LoginFilter loginFilter = new MockLoginFilter();
+        LoginFilter loginFilter = new UsernameFilterGeneric();
         loginFilter.onInvalidCharacter('a');
     }
 
     // This method does nothing. we only test onStop function here,
     // the callback should be tested in testFilter()
     public void testOnStop() {
-        LoginFilter loginFilter = new MockLoginFilter();
+        LoginFilter loginFilter = new UsernameFilterGeneric();
         loginFilter.onStop();
     }
 
     // This method does nothing. we only test onStart function here,
     // the callback should be tested in testFilter()
     public void testOnStart() {
-        LoginFilter loginFilter = new LoginFilter.UsernameFilterGeneric();
+        LoginFilter loginFilter = new UsernameFilterGeneric();
         loginFilter.onStart();
     }
-
-    private final class MockLoginFilter extends LoginFilter.UsernameFilterGeneric {
-        private int mInvalidCharacterCount;
-        private boolean mIsStarted = false;
-        private boolean mIsStopped = false;
-
-        public MockLoginFilter() {
-            super();
-        }
-
-        public MockLoginFilter(boolean appendInvalid) {
-            super(appendInvalid);
-        }
-
-        @Override
-        public void onInvalidCharacter(char c) {
-            mInvalidCharacterCount++;
-            super.onInvalidCharacter(c);
-        }
-
-        public int getInvalidCharacterCount() {
-            return mInvalidCharacterCount;
-        }
-
-        @Override
-        public void onStart() {
-            mIsStarted = true;
-            super.onStart();
-        }
-
-        public boolean isStarted() {
-            return mIsStarted;
-        }
-
-        @Override
-        public void onStop() {
-            mIsStopped = true;
-            super.onStop();
-        }
-
-        public boolean isStopped() {
-            return mIsStopped;
-        }
-
-        public void reset() {
-            mInvalidCharacterCount = 0;
-            mIsStarted = false;
-            mIsStopped = false;
-        }
-    }
 }
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java b/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
index 14bcc8e..020dd88 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
@@ -16,8 +16,6 @@
 
 package android.text.cts;
 
-import java.util.ArrayList;
-
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.Html;
@@ -29,6 +27,8 @@
 import android.text.style.ParagraphStyle;
 import android.text.style.QuoteSpan;
 
+import java.util.ArrayList;
+
 /**
  * Test {@link SpannableStringBuilder}.
  */
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java b/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
index 6dee5e9..09b5dbf 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
@@ -21,19 +21,20 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.Editable;
 import android.text.InputFilter;
+import android.text.Selection;
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.TextWatcher;
 import android.text.style.BulletSpan;
-import android.text.style.ParagraphStyle;
 import android.text.style.QuoteSpan;
-import android.text.style.RelativeSizeSpan;
 import android.text.style.StrikethroughSpan;
 import android.text.style.SubscriptSpan;
 import android.text.style.TabStopSpan;
 import android.text.style.UnderlineSpan;
 
+import java.util.Arrays;
+
 /**
  * Test {@link SpannableStringBuilder}.
  */
@@ -377,6 +378,28 @@
         }
     }
 
+    @SmallTest
+    public void testAppend_textWithSpan() {
+        final QuoteSpan span = new QuoteSpan();
+        final SpannableStringBuilder builder = new SpannableStringBuilder("hello ");
+        final int spanStart = builder.length();
+        builder.append("planet", span, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        final int spanEnd = builder.length();
+        builder.append(" earth");
+
+        assertEquals("SpannableStringBuilder.append should append text to existing whole text",
+                "hello planet earth", builder.toString());
+
+        final Object[] spans = builder.getSpans(0, builder.length(), Object.class);
+        assertNotNull("Appended text included a Quote span", spans);
+        assertEquals("Appended text included a Quote span", 1, spans.length);
+        assertSame("Should be the same span instance", span, spans[0]);
+        assertEquals("Appended span should start at appended text start",
+                spanStart, builder.getSpanStart(spans[0]));
+        assertEquals("Appended span should end at appended text end",
+                spanEnd, builder.getSpanEnd(spans[0]));
+    }
+
     public void testClearSpans() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world");
 
@@ -688,6 +711,19 @@
         assertEquals(0, builder.length());
     }
 
+    public void testReplace_shouldNotThrowIndexOutOfBoundsExceptionForLongText() {
+        final char[] charArray = new char[75000];
+        Arrays.fill(charArray, 'a');
+        final String text = new String(charArray, 0, 50000);
+        final String copiedText = new String(charArray);
+        final SpannableStringBuilder spannable = new SpannableStringBuilder(text);
+        Selection.setSelection(spannable, text.length());
+
+        spannable.replace(0, text.length(), copiedText);
+
+        assertEquals(copiedText.length(), spannable.length());
+    }
+
     public void testDelete() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello,world");
         assertEquals("hello,world", builder.toString());
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringTest.java b/tests/tests/text/src/android/text/cts/SpannableStringTest.java
index 1eca046..81dbf9b 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringTest.java
@@ -16,8 +16,8 @@
 
 package android.text.cts;
 
+import android.support.test.filters.SmallTest;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.style.LocaleSpan;
@@ -28,6 +28,7 @@
 
 public class SpannableStringTest extends AndroidTestCase {
 
+    @SmallTest
     public void testConstructor() {
         new SpannableString("test");
 
@@ -38,6 +39,7 @@
         }
     }
 
+    @SmallTest
     public void testValueOf() {
         String text = "test valueOf";
         SpannableString spannable = SpannableString.valueOf(text);
@@ -54,6 +56,7 @@
         }
     }
 
+    @SmallTest
     public void testSetSpan() {
         String text = "hello, world";
         SpannableString spannable = new SpannableString(text);
@@ -84,6 +87,7 @@
         }
     }
 
+    @SmallTest
     public void testRemoveSpan() {
         SpannableString spannable = new SpannableString("hello, world");
 
@@ -107,6 +111,7 @@
         assertEquals(0, spannable.getSpanFlags(underlineSpan));
     }
 
+    @SmallTest
     public void testSubSequence() {
         String text = "hello, world";
         SpannableString spannable = new SpannableString(text);
diff --git a/tests/tests/text/src/android/text/cts/Spannable_FactoryTest.java b/tests/tests/text/src/android/text/cts/Spannable_FactoryTest.java
index eca6d6d..e3ad7ca 100644
--- a/tests/tests/text/src/android/text/cts/Spannable_FactoryTest.java
+++ b/tests/tests/text/src/android/text/cts/Spannable_FactoryTest.java
@@ -18,8 +18,8 @@
 
 import android.test.AndroidTestCase;
 import android.text.Spannable;
-import android.text.SpannableString;
 import android.text.Spannable.Factory;
+import android.text.SpannableString;
 
 public class Spannable_FactoryTest extends AndroidTestCase {
 
diff --git a/tests/tests/text/src/android/text/cts/SpannedTest.java b/tests/tests/text/src/android/text/cts/SpannedTest.java
new file mode 100644
index 0000000..949ddb5
--- /dev/null
+++ b/tests/tests/text/src/android/text/cts/SpannedTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.text.cts;
+
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.SpannedString;
+import android.text.style.LocaleSpan;
+import android.text.style.QuoteSpan;
+import android.text.style.UnderlineSpan;
+
+import java.util.Locale;
+
+public class SpannedTest extends AndroidTestCase {
+
+    // Returns an array of three Spanned objects, of three different classes:
+    // SpannableString, SpannableStringBuilder, and SpannedString.
+    private static Spanned[] makeSpanned(CharSequence s) {
+        return new Spanned[]{
+                new SpannableString(s),
+                new SpannableStringBuilder(s),
+                new SpannedString(s)};
+    }
+
+    @SmallTest
+    public void testCharAt() {
+        final Spanned[] spannedCases = makeSpanned("\uD83D\uDE00");  // U+1F600 GRINNING FACE
+        for (Spanned spanned : spannedCases) {
+            assertEquals('\uD83D', spanned.charAt(0));
+            assertEquals('\uDE00', spanned.charAt(1));
+
+            try {
+                spanned.charAt(-1);
+                fail("should throw IndexOutOfBoundsException here");
+            } catch (IndexOutOfBoundsException e) {
+            }
+
+            try {
+                spanned.charAt(spanned.length());
+                fail("should throw IndexOutOfBoundsException here");
+            } catch (IndexOutOfBoundsException e) {
+            }
+        }
+    }
+
+    @SmallTest
+    public void testNextSpanTransition() {
+        final int flags = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
+        final SpannableString text = new SpannableString("0123 5678");
+        text.setSpan(new QuoteSpan(), 0, 4, flags);
+        text.setSpan(new LocaleSpan((Locale) null), 2, 7, flags);
+        text.setSpan(new UnderlineSpan(), 5, text.length(), flags);
+        // Now there are span transitions at 0, 2, 4, 5, 7, and the end of string.
+
+        final Spanned[] spannedCases = makeSpanned(text);
+        for (Spanned spanned : spannedCases) {
+
+            assertEquals(4, spanned.nextSpanTransition(1, spanned.length(), QuoteSpan.class));
+            assertEquals(spanned.length(),
+                    spanned.nextSpanTransition(4, spanned.length(), QuoteSpan.class));
+            assertEquals(5, spanned.nextSpanTransition(4, spanned.length(), UnderlineSpan.class));
+
+            assertEquals(2, spanned.nextSpanTransition(0, spanned.length(), Object.class));
+            assertEquals(4, spanned.nextSpanTransition(2, spanned.length(), Object.class));
+            assertEquals(5, spanned.nextSpanTransition(4, spanned.length(), Object.class));
+            assertEquals(7, spanned.nextSpanTransition(5, spanned.length(), Object.class));
+            assertEquals(spanned.length(),
+                    spanned.nextSpanTransition(7, spanned.length(), Object.class));
+
+            // Test that 'null' catches all spans.
+            assertEquals(2, spanned.nextSpanTransition(0, spanned.length(), null));
+            assertEquals(4, spanned.nextSpanTransition(2, spanned.length(), null));
+            assertEquals(5, spanned.nextSpanTransition(4, spanned.length(), null));
+            assertEquals(7, spanned.nextSpanTransition(5, spanned.length(), null));
+            assertEquals(spanned.length(), spanned.nextSpanTransition(7, spanned.length(), null));
+
+            // 'start' can be negative.
+            assertEquals(0, spanned.nextSpanTransition(-1, spanned.length(), QuoteSpan.class));
+
+            // 'limit' can be high.
+            final int highLimit = spanned.length() + 1;
+            assertEquals(highLimit, spanned.nextSpanTransition(5, highLimit, QuoteSpan.class));
+
+            // 'limit' can be lower than 'start'. In such a case, limit should be returned.
+            assertEquals(1, spanned.nextSpanTransition(5, 1, QuoteSpan.class));
+        }
+    }
+}
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingTest.java
index 6e89ee5..d990ffb 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingTest.java
@@ -17,12 +17,12 @@
 package android.text.cts;
 
 import android.test.AndroidTestCase;
+import android.text.Layout.Alignment;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.StaticLayout;
 import android.text.TextDirectionHeuristics;
 import android.text.TextPaint;
-import android.text.Layout.Alignment;
 import android.text.style.MetricAffectingSpan;
 import android.util.Log;
 
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index ed3f1ea..f66f4c0 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -100,8 +100,6 @@
                 maxLines);
     }
 
-
-
     /**
      * Constructor test
      */
@@ -523,37 +521,53 @@
                     TextUtils.TruncateAt.MARQUEE, 1);
             assertTrue(layout.getEllipsisCount(0) == 0);
         }
+        {
+            final String text = "\u3042" // HIRAGANA LETTER A
+                    + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
+            final float textWidth = mDefaultPaint.measureText(text);
+            final int halfWidth = (int)(textWidth / 2.0f);
+            {
+                StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
+                        halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                        SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.END, halfWidth, 1);
+                assertTrue(layout.getEllipsisCount(0) > 0);
+                assertTrue(layout.getEllipsisStart(0) > 0);
+            }
+            {
+                StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
+                        halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                        SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.START, halfWidth, 1);
+                assertTrue(layout.getEllipsisCount(0) > 0);
+                assertEquals(0, mDefaultLayout.getEllipsisStart(0));
+            }
+            {
+                StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
+                        halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                        SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.MIDDLE, halfWidth, 1);
+                assertTrue(layout.getEllipsisCount(0) > 0);
+                assertTrue(layout.getEllipsisStart(0) > 0);
+            }
+            {
+                StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
+                        halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                        SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.MARQUEE, halfWidth, 1);
+                assertEquals(0, layout.getEllipsisCount(0));
+            }
+        }
 
-        final String text = "\u3042" // HIRAGANA LETTER A
-                + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
-        final float textWidth = mDefaultPaint.measureText(text);
-        final int halfWidth = (int)(textWidth / 2.0f);
         {
-            StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
-                    halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
-                    SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.END, halfWidth, 1);
-            assertTrue(layout.getEllipsisCount(0) > 0);
-            assertTrue(layout.getEllipsisStart(0) > 0);
-        }
-        {
-            StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
-                    halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
-                    SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.START, halfWidth, 1);
-            assertTrue(layout.getEllipsisCount(0) > 0);
-            assertEquals(0, mDefaultLayout.getEllipsisStart(0));
-        }
-        {
-            StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
-                    halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
-                    SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.MIDDLE, halfWidth, 1);
-            assertTrue(layout.getEllipsisCount(0) > 0);
-            assertTrue(layout.getEllipsisStart(0) > 0);
-        }
-        {
-            StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
-                    halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
-                    SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.MARQUEE, halfWidth, 1);
-            assertEquals(0, layout.getEllipsisCount(0));
+            // The white spaces in this text will be trailing if maxLines is larger than 1, but
+            // width of the trailing white spaces must not be ignored if ellipsis is applied.
+            final String text = "abc                                             def";
+            final float textWidth = mDefaultPaint.measureText(text);
+            final int halfWidth = (int)(textWidth / 2.0f);
+            {
+                StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
+                        halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                        SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.END, halfWidth, 1);
+                assertTrue(layout.getEllipsisCount(0) > 0);
+                assertTrue(layout.getEllipsisStart(0) > 0);
+            }
         }
     }
 
diff --git a/tests/tests/text/src/android/text/cts/TextPaintTest.java b/tests/tests/text/src/android/text/cts/TextPaintTest.java
index fef492b..85fb300 100644
--- a/tests/tests/text/src/android/text/cts/TextPaintTest.java
+++ b/tests/tests/text/src/android/text/cts/TextPaintTest.java
@@ -17,6 +17,7 @@
 package android.text.cts;
 
 import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.Typeface;
 import android.test.AndroidTestCase;
 import android.text.TextPaint;
@@ -37,6 +38,11 @@
         textPaint = new TextPaint(TextPaint.DITHER_FLAG);
         assertEquals((TextPaint.DITHER_FLAG | DEFAULT_PAINT_FLAGS),
                 textPaint.getFlags());
+
+        final Paint paint = new Paint();
+        paint.setTextSize(42f);
+        textPaint = new TextPaint(paint);
+        assertEquals(paint.getTextSize(), textPaint.getTextSize());
     }
 
     public void testSet() {
diff --git a/tests/tests/text/src/android/text/cts/TextUtilsTest.java b/tests/tests/text/src/android/text/cts/TextUtilsTest.java
index 0da1eb4..77aa845 100644
--- a/tests/tests/text/src/android/text/cts/TextUtilsTest.java
+++ b/tests/tests/text/src/android/text/cts/TextUtilsTest.java
@@ -16,16 +16,19 @@
 
 package android.text.cts;
 
-
 import static android.view.View.LAYOUT_DIRECTION_LTR;
 import static android.view.View.LAYOUT_DIRECTION_RTL;
 
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import android.content.Context;
 import android.content.res.ColorStateList;
-import android.graphics.Canvas;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.FontMetricsInt;
 import android.graphics.Typeface;
+import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.test.AndroidTestCase;
@@ -41,10 +44,11 @@
 import android.text.style.ReplacementSpan;
 import android.text.style.TextAppearanceSpan;
 import android.text.style.URLSpan;
-import android.util.Log;
 import android.util.StringBuilderPrinter;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Locale;
 import java.util.regex.Pattern;
 
@@ -80,6 +84,109 @@
         return re.substring(0, re.indexOf("x"));
     }
 
+    /**
+     * @return the number of times the code unit appears in the CharSequence.
+     */
+    private int countChars(CharSequence s, char c) {
+        int count = 0;
+        for (int i = 0; i < s.length(); i++) {
+            if (s.charAt(i) == c) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public void testListEllipsize() {
+        final Context context = getContext();
+        final TextPaint paint = new TextPaint();
+        final int moreId = R.plurals.list_ellipsize_test;  // "one more" for 1, "%d more" for other
+
+        final List fullList = Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H", "I", "J");
+        final String separator = ", ";
+        final String fullString = TextUtils.join(separator, fullList);
+        final float fullWidth = paint.measureText(fullString);
+        assertEquals("",
+            TextUtils.listEllipsize(context, null, separator, paint, fullWidth, moreId));
+
+        final List<CharSequence> emptyList = new ArrayList<CharSequence>();
+        assertEquals("",
+            TextUtils.listEllipsize(context, emptyList, separator, paint, fullWidth, moreId));
+
+        // Null context should cause ellipsis to be used at the end.
+        final String ellipsizedWithNull = TextUtils.listEllipsize(
+                null, fullList, separator, paint, fullWidth / 2, 0).toString();
+        assertTrue(ellipsizedWithNull.endsWith(getEllipsis()));
+
+        // Test that the empty string gets returned if there's no space.
+        assertEquals("",
+                TextUtils.listEllipsize(context, fullList, separator, paint, 1.0f, moreId));
+
+        // Test that the full string itself can get returned if there's enough space.
+        assertEquals(fullString,
+                TextUtils.listEllipsize(context, fullList, separator, paint, fullWidth, moreId)
+                        .toString());
+        assertEquals(fullString,
+                TextUtils.listEllipsize(context, fullList, separator, paint, fullWidth * 2,
+                        moreId).toString());
+
+        final float epsilon = fullWidth / 20;
+        for (float width = epsilon; width < fullWidth - epsilon / 2; width += epsilon) {
+            final String ellipsized = TextUtils.listEllipsize(
+                    context, fullList, separator, paint, width, moreId).toString();
+            // Since we don't have the full space, test that we are not getting the full string.
+            assertFalse(fullString.equals(ellipsized));
+
+            if (!ellipsized.isEmpty()) {
+                assertTrue(ellipsized.endsWith(" more"));
+                // Test that the number of separators (which equals the number of output elements),
+                // plus the number output before more always equals the number of original elements.
+                final int lastSpace = ellipsized.lastIndexOf(' ');
+                final int penultimateSpace = ellipsized.lastIndexOf(' ', lastSpace - 1);
+                assertEquals(',', ellipsized.charAt(penultimateSpace - 1));
+                final String moreCountString = ellipsized.substring(
+                        penultimateSpace + 1, lastSpace);
+                final int moreCount = (moreCountString.equals("one"))
+                        ? 1 : Integer.parseInt(moreCountString);
+                final int commaCount = countChars(ellipsized, ',');
+                assertEquals(fullList.size(), commaCount + moreCount);
+            }
+        }
+}
+
+    public void testListEllipsize_rtl() {
+        final Context context = getContext();
+        final Resources res = context.getResources();
+        final Configuration newConfig = new Configuration(res.getConfiguration());
+
+        // save the locales and set them to just Arabic
+        final LocaleList previousLocales = newConfig.getLocales();
+        newConfig.setLocales(LocaleList.forLanguageTags("ar"));
+        res.updateConfiguration(newConfig, null);
+
+        try {
+            final TextPaint paint = new TextPaint();
+            final int moreId = R.plurals.list_ellipsize_test;  // "one more" for 1, else "%d more"
+            final String RLM = "\u200F";
+            final String LRE = "\u202A";
+            final String PDF = "\u202C";
+
+            final List fullList = Arrays.asList("A", "B");
+            final String separator = ", ";
+            final String expectedString =
+                    RLM + LRE + "A" + PDF + RLM + ", " + RLM + LRE + "B" + PDF + RLM;
+            final float enoughWidth = paint.measureText(expectedString);
+
+            assertEquals(expectedString,
+                    TextUtils.listEllipsize(context, fullList, separator, paint, enoughWidth,
+                                            moreId).toString());
+        } finally {
+            // Restore the original locales
+            newConfig.setLocales(previousLocales);
+            res.updateConfiguration(newConfig, null);
+        }
+    }
+
     public void testCommaEllipsize() {
         TextPaint p = new TextPaint();
         String text = "long, string, to, truncate";
@@ -887,10 +994,6 @@
     private class MockCharSequence implements CharSequence {
         private char mText[];
 
-        public MockCharSequence() {
-            this("");
-        }
-
         public MockCharSequence(String text) {
             mText = text.toCharArray();
         }
@@ -932,7 +1035,8 @@
                 TextUtils.getOffsetAfter(text, POS_FIRST_DBFF));
 
         // the CharSequence string has a span.
-        MockReplacementSpan mockReplacementSpan = new MockReplacementSpan();
+        ReplacementSpan mockReplacementSpan = mock(ReplacementSpan.class);
+        when(mockReplacementSpan.getSize(any(), any(), anyInt(), anyInt(), any())).thenReturn(0);
         text.setSpan(mockReplacementSpan, POS_FIRST_D800 - 1, text.length() - 1,
                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
         assertEquals(text.length() - 1, TextUtils.getOffsetAfter(text, POS_FIRST_D800));
@@ -957,21 +1061,6 @@
         }
     }
 
-    /**
-     * MockReplacementSpan for test.
-     */
-    private class MockReplacementSpan extends ReplacementSpan {
-        @Override
-        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
-                int y, int bottom, Paint paint) {
-        }
-
-        @Override
-        public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
-            return 0;
-        }
-    }
-
     public void testGetOffsetBefore() {
         // the first '\uDC00' is index 10, the second 'uDC00' is index 17
         // the '\uDFFF' is index 27
@@ -993,7 +1082,8 @@
                 TextUtils.getOffsetBefore(text, POS_FIRST_DFFF + 1));
 
         // the CharSequence string has a span.
-        MockReplacementSpan mockReplacementSpan = new MockReplacementSpan();
+        ReplacementSpan mockReplacementSpan = mock(ReplacementSpan.class);
+        when(mockReplacementSpan.getSize(any(), any(), anyInt(), anyInt(), any())).thenReturn(0);
         text.setSpan(mockReplacementSpan, 0, POS_FIRST_DC00 + 1,
                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
         assertEquals(0, TextUtils.getOffsetBefore(text, POS_FIRST_DC00));
diff --git a/tests/tests/text/src/android/text/cts/TextUtils_SimpleStringSplitterTest.java b/tests/tests/text/src/android/text/cts/TextUtils_SimpleStringSplitterTest.java
index 70bfe54..fb58c3c 100644
--- a/tests/tests/text/src/android/text/cts/TextUtils_SimpleStringSplitterTest.java
+++ b/tests/tests/text/src/android/text/cts/TextUtils_SimpleStringSplitterTest.java
@@ -16,11 +16,11 @@
 
 package android.text.cts;
 
-import java.util.Iterator;
-
 import android.test.AndroidTestCase;
 import android.text.TextUtils.SimpleStringSplitter;
 
+import java.util.Iterator;
+
 /**
  * Test {@link SimpleStringSplitter}.
  */
diff --git a/tests/tests/text/src/android/text/format/cts/FormatterTest.java b/tests/tests/text/src/android/text/format/cts/FormatterTest.java
index 6acfb84..5ae19e7 100644
--- a/tests/tests/text/src/android/text/format/cts/FormatterTest.java
+++ b/tests/tests/text/src/android/text/format/cts/FormatterTest.java
@@ -20,16 +20,18 @@
 import java.math.MathContext;
 
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.text.format.Formatter;
 
 public class FormatterTest extends AndroidTestCase {
 
+    @SmallTest
     public void testFormatFileSize() {
         // test null Context
         assertEquals("", Formatter.formatFileSize(null, 0));
 
         MathContext mc = MathContext.DECIMAL64;
-        BigDecimal bd = new BigDecimal((long) 1024, mc);
+        BigDecimal bd = new BigDecimal((long) 1000, mc);
 
         // test different long values with various length
         assertEquals("0 B", Formatter.formatFileSize(mContext, 0));
@@ -39,9 +41,9 @@
         assertEquals("99 B", Formatter.formatFileSize(mContext, 99));
         assertEquals("100 B", Formatter.formatFileSize(mContext, 100));
         assertEquals("900 B", Formatter.formatFileSize(mContext, 900));
-        assertEquals("0.88 KB", Formatter.formatFileSize(mContext, 901));
+        assertEquals("0.90 kB", Formatter.formatFileSize(mContext, 901));
 
-        assertEquals("1.00 KB", Formatter.formatFileSize(mContext, bd.pow(1).longValue()));
+        assertEquals("1.00 kB", Formatter.formatFileSize(mContext, bd.pow(1).longValue()));
 
         assertEquals("1.00 MB", Formatter.formatFileSize(mContext, bd.pow(2).longValue()));
 
@@ -51,12 +53,13 @@
 
         assertEquals("1.00 PB", Formatter.formatFileSize(mContext, bd.pow(5).longValue()));
 
-        assertEquals("1024 PB", Formatter.formatFileSize(mContext, bd.pow(6).longValue()));
+        assertEquals("1000 PB", Formatter.formatFileSize(mContext, bd.pow(6).longValue()));
 
         // test Negative value
         assertEquals("-1 B", Formatter.formatFileSize(mContext, -1));
     }
 
+    @SmallTest
     public void testFormatIpAddress() {
         assertEquals("1.0.168.192", Formatter.formatIpAddress(0xC0A80001));
         assertEquals("1.0.0.127", Formatter.formatIpAddress(0x7F000001));
diff --git a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
index b82b955..08c5596 100644
--- a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
@@ -68,15 +68,13 @@
 
         initTextViewWithNullLayout();
 
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
-                        WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+        getInstrumentation().runOnMainSync(() -> {
+            getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
+                    WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
 
-                getActivity().setContentView(mTextView);
-                mTextView.setFocusable(true);
-                mTextView.requestFocus();
-            }
+            getActivity().setContentView(mTextView);
+            mTextView.setFocusable(true);
+            mTextView.requestFocus();
         });
         getInstrumentation().waitForIdleSync();
         assertNotNull(mTextView.getLayout());
@@ -111,47 +109,35 @@
          * and checking the assertion at last.
          */
         assertSelection(-1);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Selection.removeSelection(mEditable);
-                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
-            }
+        runTestOnUiThread(() -> {
+            Selection.removeSelection(mEditable);
+            mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
         });
         getInstrumentation().waitForIdleSync();
         assertSelection(END_OF_ALL_TEXT);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Selection.removeSelection(mEditable);
-                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
-            }
+        runTestOnUiThread(() -> {
+            Selection.removeSelection(mEditable);
+            mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
         });
         getInstrumentation().waitForIdleSync();
         assertSelection(END_OF_ALL_TEXT);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setSingleLine();
-            }
-        });
+        runTestOnUiThread(mTextView::setSingleLine);
         // wait until the textView gets layout
         getInstrumentation().waitForIdleSync();
         assertNotNull(mTextView.getLayout());
         assertEquals(1, mTextView.getLayout().getLineCount());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Selection.removeSelection(mEditable);
-                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
-            }
+        runTestOnUiThread(() -> {
+            Selection.removeSelection(mEditable);
+            mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
         });
         assertSelection(END_OF_ALL_TEXT);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Selection.removeSelection(mEditable);
-                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
-            }
+        runTestOnUiThread(() -> {
+            Selection.removeSelection(mEditable);
+            mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
         });
         assertSelection(END_OF_ALL_TEXT);
     }
diff --git a/tests/tests/text/src/android/text/method/cts/BackspaceTest.java b/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
index 1705326..3a66e81 100644
--- a/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
@@ -35,22 +35,16 @@
     // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event.
     // Then update the state to the result of TextView.
     private void backspace(final EditorState state, int modifiers) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(state.mText, BufferType.EDITABLE);
-                mTextView.setKeyListener(mKeyListener);
-                mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setText(state.mText, BufferType.EDITABLE);
+            mTextView.setKeyListener(mKeyListener);
+            mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
         });
         mInstrumentation.waitForIdleSync();
         assertTrue(mTextView.hasWindowFocus());
 
         final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent));
         mInstrumentation.waitForIdleSync();
 
         state.mText = mTextView.getText();
@@ -59,6 +53,31 @@
     }
 
     @SmallTest
+    public void testCRLF() {
+        EditorState state = new EditorState();
+
+        // U+000A is LINE FEED.
+        state.setByString("U+000A |");
+        backspace(state, 0);
+        state.assertEquals("|");
+
+        // U+000D is CARRIAGE RETURN.
+        state.setByString("U+000D |");
+        backspace(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("U+000D U+000A |");
+        backspace(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("U+000A U+000D |");
+        backspace(state, 0);
+        state.assertEquals("U+000A |");
+        backspace(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
     public void testSurrogatePairs() {
         EditorState state = new EditorState();
 
diff --git a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
index d913cf9..146f3d5 100644
--- a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
@@ -16,12 +16,13 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import android.cts.util.CtsKeyEventUtil;
 import android.os.SystemClock;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
+import android.text.SpannableStringBuilder;
 import android.text.method.BaseKeyListener;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -33,20 +34,12 @@
 public class BaseKeyListenerTest extends KeyListenerTestCase {
     private static final CharSequence TEST_STRING = "123456";
 
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
     public void testBackspace() {
         testBackspace(0);
     }
 
     private void testBackspace(int modifiers) {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
         final KeyEvent event = getKey(KeyEvent.KEYCODE_DEL, modifiers);
         Editable content = Editable.Factory.getInstance().newEditable(TEST_STRING);
 
@@ -108,7 +101,7 @@
     }
 
     public void testBackspace_withAlt() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
         Editable content = Editable.Factory.getInstance().newEditable(TEST_STRING);
 
         // Delete the entire line with ALT + DEL, even if we're at the head...
@@ -132,31 +125,33 @@
     }
 
     public void testBackspace_withSendKeys() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
 
         // Delete the first character '1'
         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 1, 1);
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
         assertEquals("23456", mTextView.getText().toString());
 
         // Delete character '2' and '3'
         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 1, 3);
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
         assertEquals("1456", mTextView.getText().toString());
 
         // Delete everything on the line the cursor is on.
         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 0, 0);
-        sendAltDelete();
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(
+                mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_ALT_LEFT);
         assertEquals("", mTextView.getText().toString());
 
         // ALT+DEL deletes the selection only.
         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 2, 4);
-        sendAltDelete();
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(
+                mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_ALT_LEFT);
         assertEquals("1256", mTextView.getText().toString());
 
         // DEL key does not take effect when TextView does not have BaseKeyListener.
         prepTextViewSync(TEST_STRING, null, true, 1, 1);
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
         assertEquals(TEST_STRING, mTextView.getText().toString());
     }
 
@@ -166,7 +161,7 @@
     }
 
     public void testBackspace_withCtrl() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
 
         // If the contents only having symbolic characters, delete all characters.
         String testText = "!#$%&'()`{*}_?+";
@@ -321,7 +316,7 @@
     }
 
     public void testForwardDelete_withCtrl() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
 
         // If the contents only having symbolic characters, delete all characters.
         String testText = "!#$%&'()`{*}_?+";
@@ -502,41 +497,64 @@
      * 3. ACTION_MULTIPLE KEYCODE_UNKNOWN by inserting the event's text into the content.
      */
     public void testPressKey() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
 
         // press '0' key.
         prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 0, 0);
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_0);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_0);
         assertEquals("123456", mTextView.getText().toString());
 
         // delete character '2'
         prepTextViewSync(mTextView.getText(), mockBaseKeyListener, true, 1, 2);
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
         assertEquals("13456", mTextView.getText().toString());
 
         // test ACTION_MULTIPLE KEYCODE_UNKNOWN key event.
         KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(), "abcd",
                 KeyCharacterMap.BUILT_IN_KEYBOARD, 0);
         prepTextViewSync(mTextView.getText(), mockBaseKeyListener, true, 2, 2);
-        mKeyEventUtil.sendKey(mTextView, event);
+        CtsKeyEventUtil.sendKey(mInstrumentation, mTextView, event);
         mInstrumentation.waitForIdleSync();
         // the text of TextView is never changed, onKeyOther never works.
 //        assertEquals("13abcd456", mTextView.getText().toString());
     }
 
-    private void executeAltBackspace(Editable content, MockBaseKeyListener listener) {
+    public void testOnKeyOther() {
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+        final String string = "abc";
+        final SpannableStringBuilder content = new SpannableStringBuilder(string);
+
+        KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_UNKNOWN);
+        assertFalse(mockBaseKeyListener.onKeyOther(mTextView, content, event));
+        assertEquals(string, content.toString());
+
+        event = new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_0);
+        assertFalse(mockBaseKeyListener.onKeyOther(mTextView, content, event));
+        assertEquals(string, content.toString());
+
+        Selection.setSelection(content, 1, 0);
+        event = new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_UNKNOWN);
+        assertFalse(mockBaseKeyListener.onKeyOther(mTextView, content, event));
+        assertEquals(string, content.toString());
+
+        event = new KeyEvent(SystemClock.uptimeMillis(), "b", 0, 0);
+        assertTrue(mockBaseKeyListener.onKeyOther(mTextView, content, event));
+        assertEquals("bbc", content.toString());
+    }
+
+    private void executeAltBackspace(Editable content, BaseKeyListener listener) {
         final KeyEvent delKeyEvent = getKey(KeyEvent.KEYCODE_DEL,
                 KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON);
         listener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, delKeyEvent);
     }
 
-    private void executeCtrlBackspace(Editable content, MockBaseKeyListener listener) {
+    private void executeCtrlBackspace(Editable content, BaseKeyListener listener) {
         final KeyEvent delKeyEvent = getKey(KeyEvent.KEYCODE_DEL,
                 KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON);
         listener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, delKeyEvent);
     }
 
-    private void executeCtrlForwardDelete(Editable content, MockBaseKeyListener listener) {
+    private void executeCtrlForwardDelete(Editable content, BaseKeyListener listener) {
         final KeyEvent delKeyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL,
                 KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON);
         listener.forwardDelete(mTextView, content, KeyEvent.KEYCODE_FORWARD_DEL, delKeyEvent);
@@ -548,34 +566,18 @@
      */
     private void prepTextViewSync(final CharSequence content, final BaseKeyListener keyListener,
             final boolean selectInTextView, final int selectionStart, final int selectionEnd) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(content, BufferType.EDITABLE);
-                mTextView.setKeyListener(keyListener);
-                Selection.setSelection(
-                        (Spannable) (selectInTextView ? mTextView.getText() : content),
-                        selectionStart, selectionEnd);
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setText(content, BufferType.EDITABLE);
+            mTextView.setKeyListener(keyListener);
+            Selection.setSelection(
+                    selectInTextView ? mTextView.getText() : (Spannable) content,
+                    selectionStart, selectionEnd);
         });
         mInstrumentation.waitForIdleSync();
         assertTrue(mTextView.hasWindowFocus());
     }
 
     /**
-     * Sends alt-delete key combo via {@link #sendKeys(int... keys)}.
-     */
-    private void sendAltDelete() {
-        mKeyEventUtil.sendKey(mTextView, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_ALT_LEFT));
-        mKeyEventUtil.sendKey(mTextView, new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_DEL, 0, KeyEvent.META_ALT_ON));
-        mKeyEventUtil.sendKey(mTextView, new KeyEvent(0, 0, KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_DEL, 0, KeyEvent.META_ALT_ON));
-        mKeyEventUtil.sendKey(mTextView, new KeyEvent(KeyEvent.ACTION_UP,
-                KeyEvent.KEYCODE_ALT_LEFT));
-    }
-
-    /**
      * A mocked {@link android.text.method.BaseKeyListener} for testing purposes.
      */
     private class MockBaseKeyListener extends BaseKeyListener {
diff --git a/tests/tests/text/src/android/text/method/cts/BaseMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/BaseMovementMethodTest.java
new file mode 100644
index 0000000..4c5300a
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/BaseMovementMethodTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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.text.method.cts;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.widget.TextView.BufferType.EDITABLE;
+
+import static org.junit.Assert.*;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.cts.util.WidgetTestUtils;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.Spannable;
+import android.text.method.BaseMovementMethod;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerProperties;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link BaseMovementMethod}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class BaseMovementMethodTest {
+
+    private BaseMovementMethod mMovementMethod;
+
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
+
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setUp() throws Exception {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mMovementMethod = new BaseMovementMethod();
+    }
+
+    @MediumTest
+    @Test
+    public void testOnGenericMotionEvent_horizontalScroll() {
+        final String testLine = "some text some text";
+        final String testString = testLine + "\n" + testLine;
+
+        final TextView textView = createTextView();
+        // limit lines for horizontal scroll
+        textView.setSingleLine();
+        textView.setText(testString, EDITABLE);
+
+        // limit width for horizontal scroll
+
+        setContentView(textView, (int) textView.getPaint().measureText(testLine) / 3);
+        // assert the default scroll position
+        assertEquals(0, textView.getScrollX());
+
+        final Spannable text = (Spannable) textView.getText();
+        final double lineSpacing = Math.ceil(textView.getPaint().getFontSpacing());
+
+        // scroll right
+        MotionEvent event = createScrollEvent(1, 0);
+        assertTrue(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, textView, null);
+        assertEquals(lineSpacing, textView.getScrollX(), lineSpacing / 4);
+        event.recycle();
+
+        // scroll left
+        event = createScrollEvent(-1, 0);
+        assertTrue(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, textView, null);
+        assertEquals(0, textView.getScrollX());
+        event.recycle();
+
+        // cannot scroll to left
+        event = createScrollEvent(-1, 0);
+        assertFalse(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        event.recycle();
+
+        // cannot scroll to right
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, textView,
+                () -> textView.scrollTo((int) textView.getLayout().getLineWidth(0), 0));
+        event = createScrollEvent(1, 0);
+        assertFalse(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        event.recycle();
+
+        // meta shift on
+        // reset scroll
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, textView,
+                () -> textView.scrollTo(0, 0));
+
+        // scroll top becomes scroll right
+        event = createScrollEvent(0, 1, KeyEvent.META_SHIFT_ON);
+        assertTrue(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, textView, null);
+        assertEquals(lineSpacing, textView.getScrollX(), lineSpacing / 4);
+        event.recycle();
+
+        // scroll down becomes scroll left
+        event = createScrollEvent(0, -1, KeyEvent.META_SHIFT_ON);
+        assertTrue(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, textView, null);
+        assertEquals(0, textView.getScrollX());
+        event.recycle();
+    }
+
+    @MediumTest
+    @Test
+    public void testOnGenericMotionEvent_verticalScroll() {
+        final String testLine = "some text some text";
+        final String testString = testLine + "\n" + testLine;
+
+        final TextView textView = createTextView();
+        // limit lines for vertical scroll
+        textView.setMaxLines(1);
+        textView.setText(testString, EDITABLE);
+        setContentView(textView, WRAP_CONTENT);
+        // assert the default scroll positions
+        assertEquals(0, textView.getScrollY());
+
+        final Spannable text = (Spannable) textView.getText();
+        final int lineHeight = textView.getLineHeight();
+
+        // scroll down
+        MotionEvent event = createScrollEvent(0, -1);
+        assertTrue(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, textView, null);
+        assertEquals(lineHeight, textView.getScrollY(), lineHeight / 4);
+        event.recycle();
+
+        // scroll up
+        event = createScrollEvent(0, 1);
+        assertTrue(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, textView, null);
+        assertEquals(0, textView.getScrollY());
+        event.recycle();
+
+        // cannot scroll up
+        event = createScrollEvent(0, 1);
+        assertFalse(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        event.recycle();
+
+        // cannot scroll down
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, textView,
+                () -> textView.scrollTo(0, textView.getLayout().getHeight()));
+        event = createScrollEvent(0, -1);
+        assertFalse(mMovementMethod.onGenericMotionEvent(textView, text, event));
+        event.recycle();
+    }
+
+    private TextView createTextView() {
+        final TextView textView = new TextViewNoIme(mActivityRule.getActivity());
+        textView.setFocusable(true);
+        textView.setMovementMethod(mMovementMethod);
+        textView.setTextDirection(View.TEXT_DIRECTION_LTR);
+        return textView;
+    }
+
+    private void setContentView(@NonNull TextView textView, int textWidth) {
+        final Activity activity = mActivityRule.getActivity();
+        final FrameLayout layout = new FrameLayout(activity);
+        layout.addView(textView, new ViewGroup.LayoutParams(textWidth, WRAP_CONTENT));
+
+        mInstrumentation.runOnMainSync(() -> {
+            activity.setContentView(layout, new ViewGroup.LayoutParams(MATCH_PARENT,
+                    MATCH_PARENT));
+            textView.requestFocus();
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(textView.isFocused());
+    }
+
+    private static MotionEvent createScrollEvent(int horizontal, int vertical) {
+        return createScrollEvent(horizontal, vertical, 0);
+    }
+
+    private static MotionEvent createScrollEvent(int horizontal, int vertical, int meta) {
+        final PointerProperties[] pointerProperties = new PointerProperties[1];
+        pointerProperties[0] = new PointerProperties();
+        pointerProperties[0].id = 0;
+        final MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1];
+        coords[0] = new MotionEvent.PointerCoords();
+        coords[0].setAxisValue(MotionEvent.AXIS_VSCROLL, vertical);
+        coords[0].setAxisValue(MotionEvent.AXIS_HSCROLL, horizontal);
+        final long time = SystemClock.uptimeMillis();
+        return MotionEvent.obtain(time, time, MotionEvent.ACTION_SCROLL, 1,
+                pointerProperties, coords, meta, 0, 1.0f, 1.0f, 0, 0,
+                InputDevice.SOURCE_CLASS_POINTER, 0);
+    }
+}
diff --git a/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
index 7642d91..fd2761e 100644
--- a/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
@@ -16,7 +16,7 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import android.cts.util.CtsKeyEventUtil;
 import android.text.InputType;
 import android.text.method.DateKeyListener;
 import android.view.KeyEvent;
@@ -26,14 +26,6 @@
  */
 public class DateKeyListenerTest extends KeyListenerTestCase {
 
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
     public void testConstructor() {
         new DateKeyListener();
     }
@@ -77,26 +69,26 @@
         assertEquals("", mTextView.getText().toString());
 
         // press '1' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_1);
         assertEquals("1", mTextView.getText().toString());
 
         // press '2' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_2);
         assertEquals("12", mTextView.getText().toString());
 
         // press an unaccepted key if it exists.
         int keyCode = TextMethodUtils.getUnacceptedKeyCode(DateKeyListener.CHARACTERS);
         if (-1 != keyCode) {
-            mKeyEventUtil.sendKeys(mTextView, keyCode);
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, keyCode);
             assertEquals("12", mTextView.getText().toString());
         }
 
         // press '-' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_MINUS);
         assertEquals("12-", mTextView.getText().toString());
 
         // press '/' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_SLASH);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_SLASH);
         assertEquals("12-/", mTextView.getText().toString());
 
         // remove DateKeyListener
@@ -104,7 +96,7 @@
         assertEquals("12-/", mTextView.getText().toString());
 
         // press '/' key, it will not be accepted.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_SLASH);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_SLASH);
         assertEquals("12-/", mTextView.getText().toString());
     }
 
diff --git a/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
index 9dfc38a..6276125 100644
--- a/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
@@ -16,7 +16,7 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import android.cts.util.CtsKeyEventUtil;
 import android.text.InputType;
 import android.text.method.DateTimeKeyListener;
 import android.view.KeyCharacterMap;
@@ -27,14 +27,6 @@
  */
 public class DateTimeKeyListenerTest extends KeyListenerTestCase {
 
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
     public void testConstructor() {
         new DateTimeKeyListener();
     }
@@ -80,12 +72,12 @@
         assertEquals(expectedText, mTextView.getText().toString());
 
         // press '1' key.
-        mKeyEventUtil.sendString(mTextView, "1");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "1");
         expectedText += "1";
         assertEquals(expectedText, mTextView.getText().toString());
 
         // press '2' key.
-        mKeyEventUtil.sendString(mTextView, "2");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "2");
         expectedText += "2";
         assertEquals(expectedText, mTextView.getText().toString());
 
@@ -93,28 +85,28 @@
         KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
         if ('a' == kcm.getMatch(KeyEvent.KEYCODE_A, DateTimeKeyListener.CHARACTERS)) {
             expectedText += "a";
-            mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_A);
+            CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_A);
             assertEquals(expectedText, mTextView.getText().toString());
         }
 
         // press 'p' key if producible
         if ('p' == kcm.getMatch(KeyEvent.KEYCODE_P, DateTimeKeyListener.CHARACTERS)) {
             expectedText += "p";
-            mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_P);
+            CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_P);
             assertEquals(expectedText, mTextView.getText().toString());
         }
 
         // press 'm' key if producible
         if ('m' == kcm.getMatch(KeyEvent.KEYCODE_M, DateTimeKeyListener.CHARACTERS)) {
             expectedText += "m";
-            mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_M);
+            CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_M);
             assertEquals(expectedText, mTextView.getText().toString());
         }
 
         // press an unaccepted key if it exists.
         int keyCode = TextMethodUtils.getUnacceptedKeyCode(DateTimeKeyListener.CHARACTERS);
         if (-1 != keyCode) {
-            mKeyEventUtil.sendKeys(mTextView, keyCode);
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, keyCode);
             assertEquals(expectedText, mTextView.getText().toString());
         }
 
@@ -122,7 +114,7 @@
         setKeyListenerSync(null);
         assertEquals(expectedText, mTextView.getText().toString());
 
-        mKeyEventUtil.sendString(mTextView, "1");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "1");
         assertEquals(expectedText, mTextView.getText().toString());
     }
 
diff --git a/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
index 3170482..2587b60 100644
--- a/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
@@ -16,7 +16,7 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import android.cts.util.CtsKeyEventUtil;
 import android.text.InputType;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -29,14 +29,6 @@
  */
 public class DigitsKeyListenerTest extends KeyListenerTestCase {
 
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
     public void testConstructor() {
         new DigitsKeyListener();
 
@@ -403,19 +395,19 @@
         assertEquals("", mTextView.getText().toString());
 
         // press '-' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_MINUS);
         assertEquals("", mTextView.getText().toString());
 
         // press '1' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_1);
         assertEquals("1", mTextView.getText().toString());
 
         // press '.' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PERIOD);
         assertEquals("1", mTextView.getText().toString());
 
         // press '2' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_2);
         assertEquals("12", mTextView.getText().toString());
     }
 
@@ -437,27 +429,27 @@
         assertEquals("", mTextView.getText().toString());
 
         // press '-' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_MINUS);
         assertEquals("-", mTextView.getText().toString());
 
         // press '1' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_1);
         assertEquals("-1", mTextView.getText().toString());
 
         // press '.' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PERIOD);
         assertEquals("-1", mTextView.getText().toString());
 
         // press '+' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PLUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PLUS);
         assertEquals("-1", mTextView.getText().toString());
 
         // press '2' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_2);
         assertEquals("-12", mTextView.getText().toString());
 
         // press '-' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_MINUS);
         assertEquals("-12", mTextView.getText().toString());
     }
 
@@ -479,27 +471,27 @@
         assertEquals("", mTextView.getText().toString());
 
         // press '-' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_MINUS);
         assertEquals("", mTextView.getText().toString());
 
         // press '+' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PLUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PLUS);
         assertEquals("", mTextView.getText().toString());
 
         // press '1' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_1);
         assertEquals("1", mTextView.getText().toString());
 
         // press '.' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PERIOD);
         assertEquals("1.", mTextView.getText().toString());
 
         // press '2' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_2);
         assertEquals("1.2", mTextView.getText().toString());
 
         // press '.' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PERIOD);
         assertEquals("1.2", mTextView.getText().toString());
     }
 
@@ -523,27 +515,27 @@
         assertEquals("", mTextView.getText().toString());
 
         // press '+' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PLUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PLUS);
         assertEquals("+", mTextView.getText().toString());
 
         // press '1' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_1);
         assertEquals("+1", mTextView.getText().toString());
 
         // press '.' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PERIOD);
         assertEquals("+1.", mTextView.getText().toString());
 
         // press '2' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_2);
         assertEquals("+1.2", mTextView.getText().toString());
 
         // press '-' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_MINUS);
         assertEquals("+1.2", mTextView.getText().toString());
 
         // press '.' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PERIOD);
         assertEquals("+1.2", mTextView.getText().toString());
     }
 
@@ -564,33 +556,31 @@
         assertEquals("", mTextView.getText().toString());
 
         // press '1' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_1);
         assertEquals("", mTextView.getText().toString());
 
         // press '5' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_5);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_5);
         assertEquals("5", mTextView.getText().toString());
 
         // press '.' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PERIOD);
         assertEquals("5", mTextView.getText().toString());
 
         // press '-' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_MINUS);
         assertEquals("5", mTextView.getText().toString());
 
         // remove DigitsKeyListener
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(null);
-                mTextView.requestFocus();
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setKeyListener(null);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
         assertEquals("5", mTextView.getText().toString());
 
         // press '5' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_5);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_5);
         assertEquals("5", mTextView.getText().toString());
     }
 
diff --git a/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java b/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
index 40ed593..50250ea 100644
--- a/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
@@ -35,22 +35,16 @@
     // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event.
     // Then update the state to the result of TextView.
     private void forwardDelete(final EditorState state, int modifiers) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(state.mText, BufferType.EDITABLE);
-                mTextView.setKeyListener(mKeyListener);
-                mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setText(state.mText, BufferType.EDITABLE);
+            mTextView.setKeyListener(mKeyListener);
+            mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
         });
         mInstrumentation.waitForIdleSync();
         assertTrue(mTextView.hasWindowFocus());
 
         final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent));
         mInstrumentation.waitForIdleSync();
 
         state.mText = mTextView.getText();
@@ -59,6 +53,30 @@
     }
 
     @SmallTest
+    public void testCRLF() {
+        EditorState state = new EditorState();
+
+        // U+000A is LINE FEED.
+        state.setByString("| U+000A");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // U+000D is CARRIAGE RETURN.
+        state.setByString("| U+000D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+000D U+000A");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+000A U+000D");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+000D");
+        forwardDelete(state, 0);
+    }
+
+    @SmallTest
     public void testSurrogatePairs() {
         EditorState state = new EditorState();
 
diff --git a/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java b/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
index ec9c48b..ea503f3 100644
--- a/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
+++ b/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
@@ -34,7 +34,7 @@
  * {@link MultiTapKeyListenerTest}
  * {@link NumberKeyListenerTest}
  * {@link QwertyKeyListenerTest}
- * {@link TextKeyKeyListenerTest}
+ * {@link TextKeyListenerTest}
  *
  * @see BaseKeyListenerTest
  * @see DateKeyListenerTest
@@ -43,7 +43,7 @@
  * @see MultiTapKeyListenerTest
  * @see NumberKeyListenerTest
  * @see QwertyKeyListenerTest
- * @see TextKeyKeyListenerTest
+ * @see TextKeyListenerTest
  */
 public abstract class KeyListenerTestCase extends
         ActivityInstrumentationTestCase2<KeyListenerCtsActivity> {
@@ -63,12 +63,8 @@
         mInstrumentation = getInstrumentation();
         mTextView = (EditText) mActivity.findViewById(R.id.keylistener_textview);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Ensure that the screen is on for this test.
-                mTextView.setKeepScreenOn(true);
-            }
-        });
+        // Ensure that the screen is on for this test.
+        mInstrumentation.runOnMainSync(() -> mTextView.setKeepScreenOn(true));
         mInstrumentation.waitForIdleSync();
         assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS));
     }
@@ -77,11 +73,7 @@
      * Synchronously sets mTextView's key listener on the UI thread.
      */
     protected void setKeyListenerSync(final KeyListener keyListener) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(keyListener);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mTextView.setKeyListener(keyListener));
         mInstrumentation.waitForIdleSync();
     }
 
diff --git a/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
index 03fc1e7..34533f9 100644
--- a/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
@@ -34,6 +34,9 @@
 import android.widget.TextView;
 import android.widget.TextView.BufferType;
 
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
 /**
  * Test {@link LinkMovementMethod}. The class is an implementation of interface
  * {@link MovementMethod}. The typical usage of {@link MovementMethod} is tested in
@@ -52,9 +55,9 @@
 
     private Spannable mSpannable;
 
-    private MockClickableSpan mClickable0;
+    private ClickableSpan mClickable0;
 
-    private MockClickableSpan mClickable1;
+    private ClickableSpan mClickable1;
 
     public LinkMovementMethodTest() {
         super("android.text.cts", CtsActivity.class);
@@ -69,11 +72,7 @@
         mView = new TextViewNoIme(getActivity());
         mView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
         mView.setText(CONTENT, BufferType.SPANNABLE);
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                getActivity().setContentView(mView);
-            }
-        });
+        getInstrumentation().runOnMainSync(() -> getActivity().setContentView(mView));
         getInstrumentation().waitForIdleSync();
 
         mSpannable = (Spannable) mView.getText();
@@ -142,51 +141,51 @@
     public void testOnKeyDown() {
         // no selection
         assertSelection(mSpannable, -1);
-        mClickable0.reset();
-        mClickable1.reset();
+        reset(mClickable0);
+        reset(mClickable1);
         assertFalse(mMethod.onKeyDown(mView, mSpannable, KeyEvent.KEYCODE_ENTER,
                 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)));
-        assertFalse(mClickable0.hasCalledOnClick());
-        assertFalse(mClickable1.hasCalledOnClick());
+        verify(mClickable0, never()).onClick(any());
+        verify(mClickable1, never()).onClick(any());
 
         // select clickable0
         Selection.setSelection(mSpannable, mSpannable.getSpanStart(mClickable0),
                 mSpannable.getSpanEnd(mClickable0));
-        mClickable0.reset();
-        mClickable1.reset();
+        reset(mClickable0);
+        reset(mClickable1);
         assertFalse(mMethod.onKeyDown(mView, mSpannable, KeyEvent.KEYCODE_DPAD_CENTER,
                 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER)));
-        assertTrue(mClickable0.hasCalledOnClick());
-        assertFalse(mClickable1.hasCalledOnClick());
+        verify(mClickable0, times(1)).onClick(any());
+        verify(mClickable1, never()).onClick(any());
 
         // select unclickable
         Selection.setSelection(mSpannable, mSpannable.getSpanEnd(mClickable0),
                 mSpannable.getSpanStart(mClickable1));
-        mClickable0.reset();
-        mClickable1.reset();
+        reset(mClickable0);
+        reset(mClickable1);
         assertFalse(mMethod.onKeyDown(mView, mSpannable, KeyEvent.KEYCODE_ENTER,
                 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)));
-        assertFalse(mClickable0.hasCalledOnClick());
-        assertFalse(mClickable1.hasCalledOnClick());
+        verify(mClickable0, never()).onClick(any());
+        verify(mClickable1, never()).onClick(any());
 
         // select all clickables(more than one)
         Selection.selectAll(mSpannable);
-        mClickable0.reset();
-        mClickable1.reset();
+        reset(mClickable0);
+        reset(mClickable1);
         assertFalse(mMethod.onKeyDown(mView, mSpannable, KeyEvent.KEYCODE_DPAD_CENTER,
                 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER)));
-        assertFalse(mClickable0.hasCalledOnClick());
-        assertFalse(mClickable1.hasCalledOnClick());
+        verify(mClickable0, never()).onClick(any());
+        verify(mClickable1, never()).onClick(any());
 
         // part of selection is clickable
         Selection.setSelection(mSpannable, mSpannable.getSpanEnd(mClickable0),
                 mSpannable.getSpanEnd(mClickable1));
-        mClickable0.reset();
-        mClickable1.reset();
+        reset(mClickable0);
+        reset(mClickable1);
         assertFalse(mMethod.onKeyDown(mView, mSpannable, KeyEvent.KEYCODE_DPAD_CENTER,
                 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER)));
-        assertFalse(mClickable0.hasCalledOnClick());
-        assertTrue(mClickable1.hasCalledOnClick());
+        verify(mClickable0, never()).onClick(any());
+        verify(mClickable1, times(1)).onClick(any());
 
         // selection contains only clickable1 and repeat count of the event is not 0
         Selection.setSelection(mSpannable, mSpannable.getSpanEnd(mClickable0),
@@ -195,11 +194,11 @@
         KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_DPAD_CENTER, 1);
 
-        mClickable0.reset();
-        mClickable1.reset();
+        reset(mClickable0);
+        reset(mClickable1);
         assertFalse(mMethod.onKeyDown(mView, mSpannable, KeyEvent.KEYCODE_DPAD_CENTER, event));
-        assertFalse(mClickable0.hasCalledOnClick());
-        assertFalse(mClickable1.hasCalledOnClick());
+        verify(mClickable0, never()).onClick(any());
+        verify(mClickable1, never()).onClick(any());
 
         // null parameters
         try {
@@ -245,9 +244,9 @@
         assertSelectClickableLeftToRight(mSpannable, mClickable0);
 
         // release on first line
-        assertFalse(mClickable0.hasCalledOnClick());
+        verify(mClickable0, never()).onClick(any());
         assertTrue(releaseOnLine(0));
-        assertTrue(mClickable0.hasCalledOnClick());
+        verify(mClickable0, times(1)).onClick(any());
 
         // press on second line (unclickable)
         assertSelectClickableLeftToRight(mSpannable, mClickable0);
@@ -260,9 +259,9 @@
         assertSelectClickableLeftToRight(mSpannable, mClickable1);
 
         // release on last line
-        assertFalse(mClickable1.hasCalledOnClick());
+        verify(mClickable1, never()).onClick(any());
         assertTrue(releaseOnLine(2));
-        assertTrue(mClickable1.hasCalledOnClick());
+        verify(mClickable1, times(1)).onClick(any());
 
         // release on second line (unclickable)
         assertSelectClickableLeftToRight(mSpannable, mClickable1);
@@ -457,13 +456,10 @@
         }
     }
 
-    private MockClickableSpan markClickable(final int start, final int end) {
-        final MockClickableSpan clickableSpan = new MockClickableSpan();
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                mSpannable.setSpan(clickableSpan, start, end, Spanned.SPAN_MARK_MARK);
-            }
-        });
+    private ClickableSpan markClickable(final int start, final int end) {
+        final ClickableSpan clickableSpan = spy(new MockClickableSpan());
+        getInstrumentation().runOnMainSync(() -> mSpannable.setSpan(clickableSpan, start, end,
+                Spanned.SPAN_MARK_MARK));
         getInstrumentation().waitForIdleSync();
         return clickableSpan;
     }
@@ -495,13 +491,13 @@
     }
 
     private void assertSelectClickableLeftToRight(Spannable spannable,
-            MockClickableSpan clickableSpan) {
+            ClickableSpan clickableSpan) {
         assertSelection(spannable, spannable.getSpanStart(clickableSpan),
                 spannable.getSpanEnd(clickableSpan));
     }
 
     private void assertSelectClickableRightToLeft(Spannable spannable,
-            MockClickableSpan clickableSpan) {
+            ClickableSpan clickableSpan) {
         assertSelection(spannable,  spannable.getSpanEnd(clickableSpan),
                 spannable.getSpanStart(clickableSpan));
     }
@@ -528,20 +524,9 @@
         }
     }
 
-    private static class MockClickableSpan extends ClickableSpan {
-        private boolean mHasCalledOnClick;
-
+    public static class MockClickableSpan extends ClickableSpan {
         @Override
         public void onClick(View widget) {
-            mHasCalledOnClick = true;
-        }
-
-        public boolean hasCalledOnClick() {
-            return mHasCalledOnClick;
-        }
-
-        public void reset() {
-            mHasCalledOnClick = false;
         }
     }
 }
diff --git a/tests/tests/text/src/android/text/method/cts/MetaKeyKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/MetaKeyKeyListenerTest.java
index c6eb78c..3cfa07f 100644
--- a/tests/tests/text/src/android/text/method/cts/MetaKeyKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/MetaKeyKeyListenerTest.java
@@ -16,11 +16,13 @@
 
 package android.text.method.cts;
 
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
 import android.text.Editable;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.Spanned;
-import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.DateKeyListener;
 import android.text.method.MetaKeyKeyListener;
 import android.view.KeyCharacterMap;
@@ -191,6 +193,37 @@
                 MetaKeyKeyListener.META_SYM_ON));
     }
 
+    public void testGetMetaState_withCharSequenceAndKeyEvent() {
+        KeyEvent event = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 0,
+                KeyEvent.META_SHIFT_MASK);
+
+        assertEquals(KeyEvent.META_SHIFT_MASK, MetaKeyKeyListener.getMetaState(null, event));
+        assertEquals(KeyEvent.META_SHIFT_MASK, MetaKeyKeyListener.getMetaState("", event));
+    }
+
+    public void testGetMetaState_withCharSequenceAndMetaAndKeyEvent() {
+        KeyEvent event = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 0,
+                KeyEvent.META_CTRL_ON);
+
+        assertEquals(0, MetaKeyKeyListener.getMetaState("", MetaKeyKeyListener.META_SHIFT_ON,
+                event));
+
+        event = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 0,
+                KeyEvent.META_SHIFT_ON);
+
+        assertEquals(1, MetaKeyKeyListener.getMetaState("", MetaKeyKeyListener.META_SHIFT_ON,
+                event));
+
+        event = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 0,
+                KeyEvent.META_SYM_LOCKED);
+
+        assertEquals(2, MetaKeyKeyListener.getMetaState("", MetaKeyKeyListener.META_SYM_ON,
+                event));
+
+        assertEquals(2, MetaKeyKeyListener.getMetaState(null, MetaKeyKeyListener.META_SYM_ON,
+                event));
+    }
+
     public void testIsMetaTracker() {
         assertFalse(MetaKeyKeyListener.isMetaTracker("123456", new Object()));
         assertFalse(MetaKeyKeyListener.isMetaTracker("abc", new Object()));
@@ -206,18 +239,18 @@
     public void testResetLockedMeta() {
         MockMetaKeyKeyListener mockMetaKeyKeyListener = new MockMetaKeyKeyListener();
 
-        MockSpannable str = new MockSpannable();
+        MockSpannable str = spy(new MockSpannable());
         str.setSpan(new Object(), 0, 0, Spannable.SPAN_MARK_MARK
                 | (4 << Spannable.SPAN_USER_SHIFT));
-        assertFalse(str.hasCalledRemoveSpan());
+        verify(str, never()).removeSpan(any());
         mockMetaKeyKeyListener.callResetLockedMeta(str);
-        assertTrue(str.hasCalledRemoveSpan());
+        verify(str, atLeastOnce()).removeSpan(any());
 
-        str = new MockSpannable();
+        str = spy(new MockSpannable());
         str.setSpan(new Object(), 0, 0, Spannable.SPAN_MARK_POINT);
-        assertFalse(str.hasCalledRemoveSpan());
+        verify(str, never()).removeSpan(any());
         mockMetaKeyKeyListener.callResetLockedMeta(str);
-        assertFalse(str.hasCalledRemoveSpan());
+        verify(str, never()).removeSpan(any());
 
         try {
             mockMetaKeyKeyListener.callResetLockedMeta(null);
@@ -357,20 +390,14 @@
     /**
      * A mocked {@link android.text.Spannable} for testing purposes.
      */
-    private class MockSpannable implements Spannable {
+    public static class MockSpannable implements Spannable {
         private int mFlags;
-        private boolean mCalledRemoveSpan = false;
-
-        public boolean hasCalledRemoveSpan() {
-            return mCalledRemoveSpan;
-        }
 
         public void setSpan(Object what, int start, int end, int flags) {
             mFlags = flags;
         }
 
         public void removeSpan(Object what) {
-            mCalledRemoveSpan = true;
         }
 
         public <T> T[] getSpans(int start, int end, Class<T> type) {
diff --git a/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java
index e537b24..eaaf005 100644
--- a/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java
@@ -20,14 +20,11 @@
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
-import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.MultiTapKeyListener;
 import android.text.method.TextKeyListener.Capitalize;
 import android.view.KeyEvent;
-import android.widget.TextView;
 import android.widget.TextView.BufferType;
 
-import java.util.concurrent.TimeUnit;
 
 public class MultiTapKeyListenerTest extends KeyListenerTestCase {
     /**
@@ -49,11 +46,9 @@
         final Spannable text = new SpannableStringBuilder("123456");
 
         assertFalse(mockMultiTapKeyListener.hadAddedSpan());
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(mockMultiTapKeyListener);
-                mTextView.setText(text, BufferType.EDITABLE);
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setKeyListener(mockMultiTapKeyListener);
+            mTextView.setText(text, BufferType.EDITABLE);
         });
         mInstrumentation.waitForIdleSync();
 
@@ -169,11 +164,9 @@
     }
 
     private void prepareEmptyTextView() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("", BufferType.EDITABLE);
-                Selection.setSelection(mTextView.getEditableText(), 0, 0);
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setText("", BufferType.EDITABLE);
+            Selection.setSelection(mTextView.getEditableText(), 0, 0);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals("", mTextView.getText().toString());
@@ -181,12 +174,10 @@
 
     private void callOnKeyDown(final MultiTapKeyListener keyListener, final int keyCode,
             final int numTimes) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                for (int i = 0; i < numTimes; i++) {
-                    keyListener.onKeyDown(mTextView, mTextView.getEditableText(), keyCode,
-                            new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
-                }
+        mInstrumentation.runOnMainSync(() -> {
+            for (int i = 0; i < numTimes; i++) {
+                keyListener.onKeyDown(mTextView, mTextView.getEditableText(), keyCode,
+                        new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
             }
         });
         mInstrumentation.waitForIdleSync();
@@ -200,11 +191,7 @@
     }
 
     private void addSpace() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.append(" ");
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mTextView.append(" "));
         mInstrumentation.waitForIdleSync();
     }
 
diff --git a/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
index 09053f1..8aeefb2 100644
--- a/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
@@ -16,8 +16,7 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
-import android.text.Editable;
+import android.cts.util.CtsKeyEventUtil;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -30,14 +29,6 @@
 public class NumberKeyListenerTest extends KeyListenerTestCase {
     private MockNumberKeyListener mMockNumberKeyListener;
 
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
     /**
      * Check point:
      * 1. Filter "Android test", return "".
@@ -133,37 +124,33 @@
         final MockNumberKeyListener mockNumberKeyListener =
             new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(text, BufferType.EDITABLE);
-                mTextView.setKeyListener(mockNumberKeyListener);
-                mTextView.requestFocus();
-                Selection.setSelection((Editable) mTextView.getText(), 0, 0);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setText(text, BufferType.EDITABLE);
+            mTextView.setKeyListener(mockNumberKeyListener);
+            mTextView.requestFocus();
+            Selection.setSelection(mTextView.getText(), 0, 0);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals("123456", mTextView.getText().toString());
         // press '0' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_0);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_0);
         assertEquals("0123456", mTextView.getText().toString());
 
         // an unaccepted key if it exists.
         int keyCode = TextMethodUtils.getUnacceptedKeyCode(MockNumberKeyListener.DIGITS);
         if (-1 != keyCode) {
-            mKeyEventUtil.sendKeys(mTextView, keyCode);
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, keyCode);
             // text of TextView will not be changed.
             assertEquals("0123456", mTextView.getText().toString());
         }
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(null);
-                mTextView.requestFocus();
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setKeyListener(null);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
         // press '0' key.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_0);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_0);
         assertEquals("0123456", mTextView.getText().toString());
     }
 
diff --git a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
index 1131e6c..b872a96 100644
--- a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
@@ -17,18 +17,16 @@
 package android.text.method.cts;
 
 
-import android.cts.util.KeyEventUtil;
+import android.app.Instrumentation;
+import android.cts.util.CtsKeyEventUtil;
 import android.cts.util.PollingCheck;
-import android.graphics.Rect;
 import android.os.ParcelFileDescriptor;
 import android.provider.Settings.SettingNotFoundException;
 import android.provider.Settings.System;
 import android.test.ActivityInstrumentationTestCase2;
-import android.text.Editable;
 import android.text.method.PasswordTransformationMethod;
 import android.util.TypedValue;
 import android.view.KeyCharacterMap;
-import android.view.View;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.LinearLayout;
@@ -38,6 +36,8 @@
 import java.io.InputStream;
 import java.util.Scanner;
 
+import static org.mockito.Mockito.*;
+
 /**
  * Test {@link PasswordTransformationMethod}.
  */
@@ -58,18 +58,18 @@
 
     private CtsActivity mActivity;
 
-    private MockPasswordTransformationMethod mMethod;
+    private PasswordTransformationMethod mMethod;
 
     private EditText mEditText;
 
     private CharSequence mTransformedText;
 
+    private Instrumentation mInstrumentation;
+
     public PasswordTransformationMethodTest() {
         super("android.text.cts", CtsActivity.class);
     }
 
-    private KeyEventUtil mKeyEventUtil;
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -80,35 +80,32 @@
                 return mActivity.hasWindowFocus();
             }
         }.run();
-        mMethod = new MockPasswordTransformationMethod();
+        mInstrumentation = getInstrumentation();
+        mMethod = spy(new PasswordTransformationMethod());
         try {
-            runTestOnUiThread(new Runnable() {
-                public void run() {
-                    EditText editText = new EditTextNoIme(mActivity);
-                    editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
-                    editText.setId(EDIT_TXT_ID);
-                    editText.setTransformationMethod(mMethod);
-                    Button button = new Button(mActivity);
-                    LinearLayout layout = new LinearLayout(mActivity);
-                    layout.setOrientation(LinearLayout.VERTICAL);
-                    layout.addView(editText, new LayoutParams(LayoutParams.MATCH_PARENT,
-                            LayoutParams.WRAP_CONTENT));
-                    layout.addView(button, new LayoutParams(LayoutParams.MATCH_PARENT,
-                            LayoutParams.WRAP_CONTENT));
-                    mActivity.setContentView(layout);
-                    editText.requestFocus();
-                }
+            runTestOnUiThread(() -> {
+                EditText editText = new EditTextNoIme(mActivity);
+                editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
+                editText.setId(EDIT_TXT_ID);
+                editText.setTransformationMethod(mMethod);
+                Button button = new Button(mActivity);
+                LinearLayout layout = new LinearLayout(mActivity);
+                layout.setOrientation(LinearLayout.VERTICAL);
+                layout.addView(editText, new LayoutParams(LayoutParams.MATCH_PARENT,
+                        LayoutParams.WRAP_CONTENT));
+                layout.addView(button, new LayoutParams(LayoutParams.MATCH_PARENT,
+                        LayoutParams.WRAP_CONTENT));
+                mActivity.setContentView(layout);
+                editText.requestFocus();
             });
         } catch (Throwable e) {
             fail("Exception thrown is UI thread:" + e.getMessage());
         }
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
         mEditText = (EditText) getActivity().findViewById(EDIT_TXT_ID);
         assertTrue(mEditText.isFocused());
 
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-
         enableAppOps();
         savePasswordPref();
         switchShowPassword(true);
@@ -117,19 +114,19 @@
     private void enableAppOps() {
         StringBuilder cmd = new StringBuilder();
         cmd.append("appops set ");
-        cmd.append(getInstrumentation().getContext().getPackageName());
+        cmd.append(mInstrumentation.getContext().getPackageName());
         cmd.append(" android:write_settings allow");
-        getInstrumentation().getUiAutomation().executeShellCommand(cmd.toString());
+        mInstrumentation.getUiAutomation().executeShellCommand(cmd.toString());
 
         StringBuilder query = new StringBuilder();
         query.append("appops get ");
-        query.append(getInstrumentation().getContext().getPackageName());
+        query.append(mInstrumentation.getContext().getPackageName());
         query.append(" android:write_settings");
         String queryStr = query.toString();
 
         String result = "No operations.";
         while (result.contains("No operations")) {
-            ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
+            ParcelFileDescriptor pfd = mInstrumentation.getUiAutomation().executeShellCommand(
                                         queryStr);
             InputStream inputStream = new FileInputStream(pfd.getFileDescriptor());
             result = convertStreamToString(inputStream);
@@ -153,50 +150,40 @@
     }
 
     public void testTextChangedCallBacks() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mTransformedText = mMethod.getTransformation(mEditText.getText(), mEditText);
-            }
+        runTestOnUiThread(() -> {
+            mTransformedText = mMethod.getTransformation(mEditText.getText(), mEditText);
         });
 
-        mMethod.reset();
+        reset(mMethod);
         // 12-key support
         KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
         if (keymap.getKeyboardType() == KeyCharacterMap.NUMERIC) {
             // "HELLO" in case of 12-key(NUMERIC) keyboard
-            mKeyEventUtil.sendKeys(mEditText, "6*4 6*3 7*5 DPAD_RIGHT 7*5 7*6 DPAD_RIGHT");
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mEditText,
+                    "6*4 6*3 7*5 DPAD_RIGHT 7*5 7*6 DPAD_RIGHT");
         }
         else {
-            mKeyEventUtil.sendKeys(mEditText, "H E 2*L O");
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mEditText, "H E 2*L O");
         }
-        assertTrue(mMethod.hasCalledBeforeTextChanged());
-        assertTrue(mMethod.hasCalledOnTextChanged());
-        assertTrue(mMethod.hasCalledAfterTextChanged());
+        verify(mMethod, atLeastOnce()).beforeTextChanged(any(), anyInt(), anyInt(), anyInt());
+        verify(mMethod, atLeastOnce()).onTextChanged(any(), anyInt(), anyInt(), anyInt());
+        verify(mMethod, atLeastOnce()).afterTextChanged(any());
 
-        mMethod.reset();
+        reset(mMethod);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mEditText.append(" ");
-            }
-        });
+        runTestOnUiThread(() -> mEditText.append(" "));
 
         // the appended string will not get transformed immediately
         // "***** "
         assertEquals("\u2022\u2022\u2022\u2022\u2022 ", mTransformedText.toString());
-        assertTrue(mMethod.hasCalledBeforeTextChanged());
-        assertTrue(mMethod.hasCalledOnTextChanged());
-        assertTrue(mMethod.hasCalledAfterTextChanged());
+        verify(mMethod, atLeastOnce()).beforeTextChanged(any(), anyInt(), anyInt(), anyInt());
+        verify(mMethod, atLeastOnce()).onTextChanged(any(), anyInt(), anyInt(), anyInt());
+        verify(mMethod, atLeastOnce()).afterTextChanged(any());
 
         // it will get transformed after a while
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                // "******"
-                return mTransformedText.toString()
-                        .equals("\u2022\u2022\u2022\u2022\u2022\u2022");
-            }
-        }.run();
+        // "******"
+        PollingCheck.waitFor(() -> mTransformedText.toString()
+                .equals("\u2022\u2022\u2022\u2022\u2022\u2022"));
     }
 
     public void testGetTransformation() {
@@ -226,18 +213,18 @@
 
     public void testOnFocusChanged() {
         // lose focus
-        mMethod.reset();
+        reset(mMethod);
         assertTrue(mEditText.isFocused());
-        mKeyEventUtil.sendKeys(mEditText, "DPAD_DOWN");
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mEditText, "DPAD_DOWN");
         assertFalse(mEditText.isFocused());
-        assertTrue(mMethod.hasCalledOnFocusChanged());
+        verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
 
         // gain focus
-        mMethod.reset();
+        reset(mMethod);
         assertFalse(mEditText.isFocused());
-        mKeyEventUtil.sendKeys(mEditText, "DPAD_UP");
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mEditText, "DPAD_UP");
         assertTrue(mEditText.isFocused());
-        assertTrue(mMethod.hasCalledOnFocusChanged());
+        verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
     }
 
     private void savePasswordPref() {
@@ -261,62 +248,4 @@
         System.putInt(mActivity.getContentResolver(), System.TEXT_SHOW_PASSWORD,
                 on ? 1 : 0);
     }
-
-    private static class MockPasswordTransformationMethod extends PasswordTransformationMethod {
-        private boolean mHasCalledBeforeTextChanged;
-
-        private boolean mHasCalledOnTextChanged;
-
-        private boolean mHasCalledAfterTextChanged;
-
-        private boolean mHasCalledOnFocusChanged;
-
-        @Override
-        public void afterTextChanged(Editable s) {
-            super.afterTextChanged(s);
-            mHasCalledAfterTextChanged = true;
-        }
-
-        @Override
-        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-            super.beforeTextChanged(s, start, count, after);
-            mHasCalledBeforeTextChanged = true;
-        }
-
-        @Override
-        public void onFocusChanged(View view, CharSequence sourceText, boolean focused,
-                int direction, Rect previouslyFocusedRect) {
-            super.onFocusChanged(view, sourceText, focused, direction, previouslyFocusedRect);
-            mHasCalledOnFocusChanged = true;
-        }
-
-        @Override
-        public void onTextChanged(CharSequence s, int start, int before, int count) {
-            super.onTextChanged(s, start, before, count);
-            mHasCalledOnTextChanged = true;
-        }
-
-        public boolean hasCalledBeforeTextChanged() {
-            return mHasCalledBeforeTextChanged;
-        }
-
-        public boolean hasCalledOnTextChanged() {
-            return mHasCalledOnTextChanged;
-        }
-
-        public boolean hasCalledAfterTextChanged() {
-            return mHasCalledAfterTextChanged;
-        }
-
-        public boolean hasCalledOnFocusChanged() {
-            return mHasCalledOnFocusChanged;
-        }
-
-        public void reset() {
-            mHasCalledBeforeTextChanged = false;
-            mHasCalledOnTextChanged = false;
-            mHasCalledAfterTextChanged = false;
-            mHasCalledOnFocusChanged = false;
-        }
-    }
 }
diff --git a/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
index 39deda3..9fc06c2 100644
--- a/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
@@ -35,7 +35,7 @@
     }
 
     public void testOnKeyDown_capitalizeNone() {
-        QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false, Capitalize.NONE);
+        final QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false, Capitalize.NONE);
 
         prepareEmptyTextView();
 
@@ -56,7 +56,7 @@
     }
 
     public void testOnKeyDown_capitalizeCharacters() {
-        QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
+        final QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
                 Capitalize.CHARACTERS);
 
         prepareEmptyTextView();
@@ -78,7 +78,7 @@
     }
 
     public void testOnKeyDown_capitalizeSentences() {
-        QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
+        final QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
                 Capitalize.SENTENCES);
 
         prepareEmptyTextView();
@@ -106,7 +106,7 @@
     }
 
     public void testOnKeyDown_capitalizeWords() {
-        QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
+        final QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
                 Capitalize.WORDS);
 
         prepareEmptyTextView();
@@ -131,31 +131,27 @@
     }
 
     private void prepareEmptyTextView() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("", BufferType.EDITABLE);
-                Selection.setSelection(mTextView.getEditableText(), 0, 0);
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setText("", BufferType.EDITABLE);
+            Selection.setSelection(mTextView.getEditableText(), 0, 0);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals("", mTextView.getText().toString());
     }
 
     private void callOnKeyDown(final QwertyKeyListener keyListener, final int keyCode) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                keyListener.onKeyDown(mTextView, mTextView.getEditableText(), keyCode,
-                        new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> keyListener.onKeyDown(mTextView,
+                mTextView.getEditableText(), keyCode,
+                new KeyEvent(KeyEvent.ACTION_DOWN, keyCode)));
         mInstrumentation.waitForIdleSync();
     }
 
     public void testGetInstance() {
-        QwertyKeyListener listener1 = QwertyKeyListener.getInstance(true, Capitalize.WORDS);
-        QwertyKeyListener listener2 = QwertyKeyListener.getInstance(true, Capitalize.WORDS);
-        QwertyKeyListener listener3 = QwertyKeyListener.getInstance(false, Capitalize.WORDS);
-        QwertyKeyListener listener4 = QwertyKeyListener.getInstance(true, Capitalize.SENTENCES);
+        final QwertyKeyListener listener1 = QwertyKeyListener.getInstance(true, Capitalize.WORDS);
+        final QwertyKeyListener listener2 = QwertyKeyListener.getInstance(true, Capitalize.WORDS);
+        final QwertyKeyListener listener3 = QwertyKeyListener.getInstance(false, Capitalize.WORDS);
+        final QwertyKeyListener listener4 = QwertyKeyListener.getInstance(true,
+                Capitalize.SENTENCES);
 
         assertNotNull(listener1);
         assertNotNull(listener2);
@@ -166,8 +162,16 @@
         assertNotSame(listener4, listener3);
     }
 
+    public void testGetInstanceForFullKeyboard() {
+        final QwertyKeyListener listener = QwertyKeyListener.getInstanceForFullKeyboard();
+
+        assertNotNull(listener);
+        // auto correct and cap flags should not be set
+        assertEquals(InputType.TYPE_CLASS_TEXT, listener.getInputType());
+    }
+
     public void testMarkAsReplaced() {
-        SpannableStringBuilder content = new SpannableStringBuilder("123456");
+        final SpannableStringBuilder content = new SpannableStringBuilder("123456");
 
         Object[] repl = content.getSpans(0, content.length(), Object.class);
         assertEquals(0, repl.length);
@@ -201,11 +205,10 @@
 
     public void testGetInputType() {
         QwertyKeyListener listener = QwertyKeyListener.getInstance(false, Capitalize.NONE);
-        int expected = InputType.TYPE_CLASS_TEXT;
-        assertEquals(expected, listener.getInputType());
+        assertEquals(InputType.TYPE_CLASS_TEXT, listener.getInputType());
 
         listener = QwertyKeyListener.getInstance(false, Capitalize.CHARACTERS);
-        expected = InputType.TYPE_CLASS_TEXT
+        final int expected = InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
         assertEquals(expected, listener.getInputType());
     }
diff --git a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
index 8419850..79d52f1 100644
--- a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
@@ -30,7 +30,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.TextView;
 import android.widget.TextView.BufferType;
@@ -73,38 +72,28 @@
     }
 
     public void testGetInstance() {
-        MovementMethod method0 = ScrollingMovementMethod.getInstance();
+        final MovementMethod method0 = ScrollingMovementMethod.getInstance();
         assertTrue(method0 instanceof ScrollingMovementMethod);
 
-        MovementMethod method1 = ScrollingMovementMethod.getInstance();
+        final MovementMethod method1 = ScrollingMovementMethod.getInstance();
         assertSame(method0, method1);
     }
 
     public void testOnTouchEventHorizontalMotion() throws Throwable {
-        /*
-         * All these assertions depends on whether the TextView has a layout.The text view will not
-         * get layout in setContent method but in otherhandler's function. Assertion which is
-         * following the setContent will not get the expecting result. It have to wait all the
-         * handlers' operations on the UiTread to finish. So all these cases are divided into
-         * several steps,setting the content at first, waiting the layout, and checking the
-         * assertion at last.
-         */
         final ScrollingMovementMethod method = new ScrollingMovementMethod();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("hello world", BufferType.SPANNABLE);
-                mTextView.setSingleLine();
-                mSpannable = (Spannable) mTextView.getText();
-                int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
-                getActivity().setContentView(mTextView,
-                        new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
-            }
+        runActionOnUiThread(() -> {
+            mTextView.setText("hello world", BufferType.SPANNABLE);
+            mTextView.setSingleLine();
+            mSpannable = (Spannable) mTextView.getText();
+            final int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
+            getActivity().setContentView(mTextView,
+                    new LayoutParams(width, LayoutParams.WRAP_CONTENT));
         });
         assertNotNull(mTextView.getLayout());
 
-        float rightMost = mTextView.getLayout().getLineRight(0) - mTextView.getWidth()
+        final float rightMost = mTextView.getLayout().getLineRight(0) - mTextView.getWidth()
                 + mTextView.getTotalPaddingLeft() + mTextView.getTotalPaddingRight();
-        int leftMost = mTextView.getScrollX();
+        final int leftMost = mTextView.getScrollX();
 
         final long now = SystemClock.uptimeMillis();
         assertTrue(getActionResult(new ActionRunnerWithResult() {
@@ -187,27 +176,17 @@
     }
 
     public void testOnTouchEventVerticalMotion() throws Throwable {
-        /*
-         * All these assertions depends on whether the TextView has a layout.The text view will not
-         * get layout in setContent method but in otherhandler's function. Assertion which is
-         * following the setContent will not get the expecting result. It have to wait all the
-         * handlers' operations on the UiTread to finish. So all these cases are divided into
-         * several steps,setting the content at first, waiting the layout, and checking the
-         * assertion at last.
-         */
         final ScrollingMovementMethod method = new ScrollingMovementMethod();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setLines(1);
-                getActivity().setContentView(mTextView,
-                        new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-            }
+        runActionOnUiThread(() -> {
+            mTextView.setLines(1);
+            getActivity().setContentView(mTextView,
+                    new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
         });
         assertNotNull(mTextView.getLayout());
 
-        float bottom = mTextView.getLayout().getHeight() - mTextView.getHeight()
+        final float bottom = mTextView.getLayout().getHeight() - mTextView.getHeight()
                 + mTextView.getTotalPaddingTop() + mTextView.getTotalPaddingBottom();
-        int top = mTextView.getScrollY();
+        final int top = mTextView.getScrollY();
 
         final long now = SystemClock.uptimeMillis();
         assertTrue(getActionResult(new ActionRunnerWithResult() {
@@ -290,75 +269,63 @@
     }
 
     public void testOnTouchEventExceptional() throws Throwable {
-        /*
-         * All these assertions depends on whether the TextView has a layout.The text view will not
-         * get layout in setContent method but in otherhandler's function. Assertion which is
-         * following the setContent will not get the expecting result. It have to wait all the
-         * handlers' operations on the UiTread to finish. So all these cases are divided into
-         * several steps,setting the content at first, waiting the layout, and checking the
-         * assertion at last.
-         */
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
-                getActivity().setContentView(mTextView,
-                        new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
-            }
+        runActionOnUiThread(() -> {
+            final int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
+            getActivity().setContentView(mTextView,
+                    new LayoutParams(width, LayoutParams.WRAP_CONTENT));
         });
         assertNotNull(mTextView.getLayout());
 
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                try {
-                    new ScrollingMovementMethod().onTouchEvent(mTextView, mSpannable, null);
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+        runActionOnUiThread(() -> {
+            try {
+                new ScrollingMovementMethod().onTouchEvent(mTextView, mSpannable, null);
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                long now = SystemClock.uptimeMillis();
-                try {
-                    new ScrollingMovementMethod().onTouchEvent(mTextView, null,
-                            MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
-
-                try {
-                    new ScrollingMovementMethod().onTouchEvent(null, mSpannable,
-                            MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
-
-                new ScrollingMovementMethod().onTouchEvent(mTextView, mSpannable,
+            long now = SystemClock.uptimeMillis();
+            try {
+                new ScrollingMovementMethod().onTouchEvent(mTextView, null,
                         MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
-                try {
-                    new ScrollingMovementMethod().onTouchEvent(null, mSpannable,
-                            MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, - 10000, 0, 0));
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                try {
-                    new ScrollingMovementMethod().onTouchEvent(mTextView, null,
-                            MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, - 10000, 0, 0));
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            try {
+                new ScrollingMovementMethod().onTouchEvent(null, mSpannable,
+                        MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                try {
-                    new ScrollingMovementMethod().onTouchEvent(null, mSpannable,
-                            MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, - 10000, 0, 0));
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            new ScrollingMovementMethod().onTouchEvent(mTextView, mSpannable,
+                    MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 0, 0, 0));
+            try {
+                new ScrollingMovementMethod().onTouchEvent(null, mSpannable,
+                        MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, -10000, 0, 0));
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                try {
-                    new ScrollingMovementMethod().onTouchEvent(mTextView, null,
-                            MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, - 10000, 0, 0));
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            try {
+                new ScrollingMovementMethod().onTouchEvent(mTextView, null,
+                        MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, -10000, 0, 0));
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
+
+            try {
+                new ScrollingMovementMethod().onTouchEvent(null, mSpannable,
+                        MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, -10000, 0, 0));
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
+
+            try {
+                new ScrollingMovementMethod().onTouchEvent(mTextView, null,
+                        MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, -10000, 0, 0));
+            } catch (NullPointerException e) {
+                // NPE is acceptable
             }
         });
     }
@@ -368,151 +335,85 @@
     }
 
     public void testOnKeyDownVerticalMovement() throws Throwable {
-        /*
-         * All these assertions depends on whether the TextView has a layout.The text view will not
-         * get layout in setContent method but in otherhandler's function. Assertion which is
-         * following the setContent will not get the expecting result. It have to wait all the
-         * handlers' operations on the UiTread to finish. So all these cases are divided into
-         * several steps,setting the content at first, waiting the layout, and checking the
-         * assertion at last.
-         */
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                getActivity().setContentView(mTextView);
-            }
-        });
+        runActionOnUiThread(() -> getActivity().setContentView(mTextView));
         assertNotNull(mTextView.getLayout());
 
         assertVisibleLineInTextView(0);
         final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_DOWN,
-                        new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN));
-            }
-        });
+        runActionOnUiThread(() -> method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_DOWN,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN)));
         assertVisibleLineInTextView(1);
 
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_UP,
-                        new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
-            }
-        });
+        runActionOnUiThread(() -> method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_UP,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP)));
         assertVisibleLineInTextView(0);
     }
 
     public void testOnKeyDownHorizontalMovement() throws Throwable {
-        /*
-         * All these assertions depends on whether the TextView has a layout.The text view will not
-         * get layout in setContent method but in otherhandler's function. Assertion which is
-         * following the setContent will not get the expecting result. It have to wait all the
-         * handlers' operations on the UiTread to finish. So all these cases are divided into
-         * several steps,setting the content at first, waiting the layout, and checking the
-         * assertion at last.
-         */
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("short");
-                mTextView.setSingleLine();
-                int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
-                getActivity().setContentView(mTextView,
-                        new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
-            }
+        runActionOnUiThread(() -> {
+            mTextView.setText("short");
+            mTextView.setSingleLine();
+            final int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
+            getActivity().setContentView(mTextView,
+                    new LayoutParams(width, LayoutParams.WRAP_CONTENT));
         });
         assertNotNull(mTextView.getLayout());
 
         final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
         int previousScrollX = mTextView.getScrollX();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onKeyDown(mTextView, (Spannable) mTextView.getText(),
-                        KeyEvent.KEYCODE_DPAD_RIGHT, new KeyEvent(KeyEvent.ACTION_DOWN,
-                                KeyEvent.KEYCODE_DPAD_RIGHT));
-            }
-        });
+        runActionOnUiThread(() -> method.onKeyDown(mTextView, (Spannable) mTextView.getText(),
+                KeyEvent.KEYCODE_DPAD_RIGHT, new KeyEvent(KeyEvent.ACTION_DOWN,
+                        KeyEvent.KEYCODE_DPAD_RIGHT)));
         assertTrue(mTextView.getScrollX() > previousScrollX);
 
         previousScrollX = mTextView.getScrollX();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onKeyDown(mTextView, (Spannable) mTextView.getText(),
-                        KeyEvent.KEYCODE_DPAD_LEFT, new KeyEvent(KeyEvent.ACTION_DOWN,
-                                KeyEvent.KEYCODE_DPAD_LEFT));
-            }
-        });
+        runActionOnUiThread(() -> method.onKeyDown(mTextView, (Spannable) mTextView.getText(),
+                KeyEvent.KEYCODE_DPAD_LEFT, new KeyEvent(KeyEvent.ACTION_DOWN,
+                        KeyEvent.KEYCODE_DPAD_LEFT)));
         assertTrue(mTextView.getScrollX() < previousScrollX);
 
         previousScrollX = mTextView.getScrollX();
         assertVisibleLineInTextView(0);
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                assertFalse(method.onKeyDown(mTextView, mSpannable, 0,
-                        new KeyEvent(KeyEvent.ACTION_DOWN, 0)));
-            }
-        });
+        runActionOnUiThread(() -> assertFalse(method.onKeyDown(mTextView, mSpannable, 0,
+                new KeyEvent(KeyEvent.ACTION_DOWN, 0))));
         assertEquals(previousScrollX, mTextView.getScrollX());
         assertVisibleLineInTextView(0);
     }
 
     public void testOnKeyDownExceptions() throws Throwable {
-        /*
-         * All these assertions depends on whether the TextView has a layout.The text view will not
-         * get layout in setContent method but in otherhandler's function. Assertion which is
-         * following the setContent will not get the expecting result. It have to wait all the
-         * handlers' operations on the UiTread to finish. So all these cases are divided into
-         * several steps,setting the content at first, waiting the layout, and checking the
-         * assertion at last.
-         */
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                getActivity().setContentView(mTextView);
-            }
-        });
+        runActionOnUiThread(() -> getActivity().setContentView(mTextView));
         assertNotNull(mTextView.getLayout());
 
         final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                try {
-                    method.onKeyDown(null, mSpannable, KeyEvent.KEYCODE_DPAD_RIGHT,
-                            new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+        runActionOnUiThread(() -> {
+            try {
+                method.onKeyDown(null, mSpannable, KeyEvent.KEYCODE_DPAD_RIGHT,
+                        new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                try {
-                    method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_RIGHT,
-                            new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            try {
+                method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_RIGHT,
+                        new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                try {
-                    method.onKeyDown(mTextView, mSpannable, KeyEvent.KEYCODE_DPAD_RIGHT, null);
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            try {
+                method.onKeyDown(mTextView, mSpannable, KeyEvent.KEYCODE_DPAD_RIGHT, null);
+            } catch (NullPointerException e) {
+                // NPE is acceptable
             }
         });
     }
 
     public void testVerticalMovement() throws Throwable {
-        /*
-         * All these assertions depends on whether the TextView has a layout.The text view will not
-         * get layout in setContent method but in otherhandler's function. Assertion which is
-         * following the setContent will not get the expecting result. It have to wait all the
-         * handlers' operations on the UiTread to finish. So all these cases are divided into
-         * several steps,setting the content at first, waiting the layout, and checking the
-         * assertion at last.
-         */
         final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setLines(1);
-                getActivity().setContentView(mTextView,
-                        new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-            }
+        runActionOnUiThread(() -> {
+            mTextView.setLines(1);
+            getActivity().setContentView(mTextView,
+                    new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
         });
         assertNotNull(mTextView.getLayout());
 
@@ -558,31 +459,29 @@
         }));
         assertVisibleLineInTextView(0);
 
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                try {
-                    method.up(null, mSpannable);
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+        runActionOnUiThread(() -> {
+            try {
+                method.up(null, mSpannable);
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                try {
-                    method.up(mTextView, null);
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            try {
+                method.up(mTextView, null);
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                try {
-                    method.down(null, mSpannable);
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            try {
+                method.down(null, mSpannable);
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                try {
-                    method.down(mTextView, null);
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            try {
+                method.down(mTextView, null);
+            } catch (NullPointerException e) {
+                // NPE is acceptable
             }
         });
     }
@@ -613,7 +512,7 @@
             // NPE is acceptable
         }
 
-        long now = SystemClock.uptimeMillis();
+        final long now = SystemClock.uptimeMillis();
         try {
             KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
             new ScrollingMovementMethod().onKeyDown(mTextView, mSpannable,
@@ -637,9 +536,9 @@
     }
 
     public void testOnTrackballEvent() {
-        long now = SystemClock.uptimeMillis();
-        MotionEvent event = MotionEvent.obtain(now, now, 0, 2, -2, 0);
-        MyScrollingMovementMethod mockMethod = new MyScrollingMovementMethod();
+        final long now = SystemClock.uptimeMillis();
+        final MotionEvent event = MotionEvent.obtain(now, now, 0, 2, -2, 0);
+        final MyScrollingMovementMethod mockMethod = new MyScrollingMovementMethod();
 
         assertFalse(mockMethod.onTrackballEvent(mTextView, mSpannable, event));
         assertFalse(mockMethod.onTrackballEvent(null, mSpannable, event));
@@ -648,10 +547,10 @@
     }
 
     public void testOnKeyUp() {
-        ScrollingMovementMethod method = new ScrollingMovementMethod();
-        SpannableString spannable = new SpannableString("Test Content");
-        KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
-        TextView view = new TextViewNoIme(getActivity());
+        final ScrollingMovementMethod method = new ScrollingMovementMethod();
+        final SpannableString spannable = new SpannableString("Test Content");
+        final KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
+        final TextView view = new TextViewNoIme(getActivity());
         view.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
 
         assertFalse(method.onKeyUp(view, spannable, KeyEvent.KEYCODE_0, event));
@@ -663,14 +562,6 @@
     }
 
     public void testOnTakeFocus() throws Throwable {
-        /*
-         * All these assertions depends on whether the TextView has a layout.The text view will not
-         * get layout in setContent method but in otherhandler's function. Assertion which is
-         * following the setContent will not get the expecting result. It have to wait all the
-         * handlers' operations on the UiTread to finish. So all these cases are divided into
-         * several steps,setting the content at first, waiting the layout, and checking the
-         * assertion at last.
-         */
         final ScrollingMovementMethod method = new ScrollingMovementMethod();
         // wait until the text view gets layout
         assertNull(mTextView.getLayout());
@@ -680,71 +571,49 @@
             // NPE is acceptable
         }
 
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                int height = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
-                getActivity().setContentView(mTextView,
-                        new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                height));
-            }
+        runActionOnUiThread(() -> {
+            final int height = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
+            getActivity().setContentView(mTextView,
+                    new LayoutParams(LayoutParams.MATCH_PARENT,
+                            height));
         });
-        Layout layout = mTextView.getLayout();
+        final Layout layout = mTextView.getLayout();
         assertNotNull(layout);
 
         int previousScrollY = mTextView.getScrollY();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onTakeFocus(mTextView, mSpannable, View.FOCUS_BACKWARD);
-            }
-        });
+        runActionOnUiThread(() -> method.onTakeFocus(mTextView, mSpannable, View.FOCUS_BACKWARD));
         assertTrue(mTextView.getScrollY() >= previousScrollY);
         assertVisibleLineInTextView(2);
 
         previousScrollY = mTextView.getScrollY();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onTakeFocus(mTextView, mSpannable, View.FOCUS_FORWARD);
-            }
-        });
+        runActionOnUiThread(() -> method.onTakeFocus(mTextView, mSpannable, View.FOCUS_FORWARD));
         assertTrue(mTextView.getScrollY() <= previousScrollY);
         assertVisibleLineInTextView(0);
 
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                try {
-                    method.onTakeFocus(null, mSpannable, View.FOCUS_FORWARD);
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+        runActionOnUiThread(() -> {
+            try {
+                method.onTakeFocus(null, mSpannable, View.FOCUS_FORWARD);
+            } catch (NullPointerException e) {
+                // NPE is acceptable
+            }
 
-                try {
-                    method.onTakeFocus(mTextView, null, View.FOCUS_FORWARD);
-                } catch (NullPointerException e) {
-                    // NPE is acceptable
-                }
+            try {
+                method.onTakeFocus(mTextView, null, View.FOCUS_FORWARD);
+            } catch (NullPointerException e) {
+                // NPE is acceptable
             }
         });
     }
 
     public void testHorizontalMovement() throws Throwable {
-        /*
-         * All these assertions depends on whether the TextView has a layout.The text view will not
-         * get layout in setContent method but in otherhandler's function. Assertion which is
-         * following the setContent will not get the expecting result. It have to wait all the
-         * handlers' operations on the UiTread to finish. So all these cases are divided into
-         * several steps,setting the content at first, waiting the layout, and checking the
-         * assertion at last.
-         */
         final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("short");
-                mTextView.setSingleLine();
-                DisplayMetrics dm = getActivity().getResources().getDisplayMetrics();
-                int width = (int) (LITTLE_SPACE * dm.scaledDensity);
-                getActivity().setContentView(mTextView,
-                        new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
-            }
+        runActionOnUiThread(() -> {
+            mTextView.setText("short");
+            mTextView.setSingleLine();
+            final DisplayMetrics dm = getActivity().getResources().getDisplayMetrics();
+            final int width = (int) (LITTLE_SPACE * dm.scaledDensity);
+            getActivity().setContentView(mTextView,
+                    new LayoutParams(width, LayoutParams.WRAP_CONTENT));
         });
         assertNotNull(mTextView.getLayout());
 
@@ -783,38 +652,26 @@
     }
 
     public void testOnKeyOther() throws Throwable {
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                getActivity().setContentView(mTextView);
-            }
-        });
+        runActionOnUiThread(() -> getActivity().setContentView(mTextView));
         assertNotNull(mTextView.getLayout());
 
         assertVisibleLineInTextView(0);
         final MyScrollingMovementMethod method = new MyScrollingMovementMethod();
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onKeyOther(mTextView, null,
-                        new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE,
-                                KeyEvent.KEYCODE_DPAD_DOWN, 2));
-            }
-        });
+        runActionOnUiThread(() -> method.onKeyOther(mTextView, null,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE,
+                        KeyEvent.KEYCODE_DPAD_DOWN, 2)));
         assertVisibleLineInTextView(1);
 
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onKeyOther(mTextView, null,
-                        new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE,
-                                KeyEvent.KEYCODE_DPAD_UP, 2));
-            }
-        });
+        runActionOnUiThread(() -> method.onKeyOther(mTextView, null,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE,
+                        KeyEvent.KEYCODE_DPAD_UP, 2)));
         assertVisibleLineInTextView(0);
     }
 
     private void assertVisibleLineInTextView(int line) {
-        Layout layout = mTextView.getLayout();
-        int scrollY = mTextView.getScrollY();
-        int padding = mTextView.getTotalPaddingTop() + mTextView.getTotalPaddingBottom();
+        final Layout layout = mTextView.getLayout();
+        final int scrollY = mTextView.getScrollY();
+        final int padding = mTextView.getTotalPaddingTop() + mTextView.getTotalPaddingBottom();
         assertTrue(layout.getLineForVertical(scrollY) <= line);
         assertTrue(layout.getLineForVertical(scrollY + mTextView.getHeight() - padding) >= line);
     }
diff --git a/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
index 19003cf..47c0a6c 100644
--- a/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
@@ -16,7 +16,7 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import android.cts.util.CtsKeyEventUtil;
 import android.os.SystemClock;
 import android.test.UiThreadTest;
 import android.text.Editable;
@@ -30,20 +30,14 @@
 import android.view.KeyEvent;
 import android.widget.TextView.BufferType;
 
+import static org.mockito.Mockito.*;
+
 public class TextKeyListenerTest extends KeyListenerTestCase {
     /**
      * time out of MultiTapKeyListener. longer than 2000ms in case the system is sluggish.
      */
     private static final long TIME_OUT = 3000;
 
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
     public void testConstructor() {
         new TextKeyListener(Capitalize.NONE, true);
 
@@ -83,20 +77,17 @@
     }
 
     public void testOnSpanAdded() {
-        final MockTextKeyListener mockTextKeyListener
-                = new MockTextKeyListener(Capitalize.CHARACTERS, true);
+        final TextKeyListener mockTextKeyListener = spy(
+                new TextKeyListener(Capitalize.CHARACTERS, true));
         final Spannable text = new SpannableStringBuilder("123456");
 
-        assertFalse(mockTextKeyListener.hadAddedSpan());
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(mockTextKeyListener);
-                mTextView.setText(text, BufferType.EDITABLE);
-            }
+        verify(mockTextKeyListener, never()).onSpanAdded(any(), any(), anyInt(), anyInt());
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setKeyListener(mockTextKeyListener);
+            mTextView.setText(text, BufferType.EDITABLE);
         });
         mInstrumentation.waitForIdleSync();
-
-        assertTrue(mockTextKeyListener.hadAddedSpan());
+        verify(mockTextKeyListener, atLeastOnce()).onSpanAdded(any(), any(), anyInt(), anyInt());
 
         mockTextKeyListener.release();
     }
@@ -152,7 +143,7 @@
         CharSequence text = "123456";
         mTextView.setText(text, BufferType.EDITABLE);
 
-        Editable content = (Editable) mTextView.getText();
+        Editable content = mTextView.getText();
         assertEquals(text, content.toString());
 
         TextKeyListener.clear(content);
@@ -187,18 +178,16 @@
         final TextKeyListener textKeyListener
                 = TextKeyListener.getInstance(false, Capitalize.NONE);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("", BufferType.EDITABLE);
-                Selection.setSelection((Editable) mTextView.getText(), 0, 0);
-                mTextView.setKeyListener(textKeyListener);
-                mTextView.requestFocus();
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setText("", BufferType.EDITABLE);
+            Selection.setSelection(mTextView.getText(), 0, 0);
+            mTextView.setKeyListener(textKeyListener);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
         assertEquals("", mTextView.getText().toString());
 
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_4);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_4);
         waitForListenerTimeout();
         String text = mTextView.getText().toString();
         int keyType = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getKeyboardType();
@@ -219,12 +208,10 @@
         final TextKeyListener textKeyListener
                 = TextKeyListener.getInstance(false, Capitalize.NONE);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("", BufferType.EDITABLE);
-                Selection.setSelection((Editable) mTextView.getText(), 0, 0);
-                mTextView.setKeyListener(textKeyListener);
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mTextView.setText("", BufferType.EDITABLE);
+            Selection.setSelection(mTextView.getText(), 0, 0);
+            mTextView.setKeyListener(textKeyListener);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals("", mTextView.getText().toString());
@@ -232,7 +219,7 @@
         // test ACTION_MULTIPLE KEYCODE_UNKNOWN key event.
         KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(), text,
                 1, KeyEvent.FLAG_WOKE_HERE);
-        mKeyEventUtil.sendKey(mTextView, event);
+        CtsKeyEventUtil.sendKey(mInstrumentation, mTextView, event);
         mInstrumentation.waitForIdleSync();
         // the text of TextView is never changed, onKeyOther never works.
 //        assertEquals(text, mTextView.getText().toString()); issue 1731439
@@ -253,27 +240,4 @@
         listener.release();
     }
 
-    /**
-     * A mocked {@link android.text.method.TextKeyListener} for testing purposes.
-     *
-     * Tracks whether {@link MockTextKeyListener#onSpanAdded(Spannable, Object, int, int)} has been
-     * called.
-     */
-    private class MockTextKeyListener extends TextKeyListener {
-        private boolean mHadAddedSpan;
-
-        public MockTextKeyListener(Capitalize cap, boolean autotext) {
-            super(cap, autotext);
-        }
-
-        @Override
-        public void onSpanAdded(Spannable s, Object what, int start, int end) {
-            mHadAddedSpan = true;
-            super.onSpanAdded(s, what, start, end);
-        }
-
-        public boolean hadAddedSpan() {
-            return mHadAddedSpan;
-        }
-    }
 }
diff --git a/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
index 4f68d54..9fed354 100644
--- a/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
@@ -16,7 +16,7 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import android.cts.util.CtsKeyEventUtil;
 import android.text.InputType;
 import android.text.method.TimeKeyListener;
 import android.view.KeyCharacterMap;
@@ -24,14 +24,6 @@
 
 public class TimeKeyListenerTest extends KeyListenerTestCase {
 
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
     public void testConstructor() {
         new TimeKeyListener();
     }
@@ -76,12 +68,12 @@
         assertEquals(expectedText, mTextView.getText().toString());
 
         // press '1' key.
-        mKeyEventUtil.sendString(mTextView, "1");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "1");
         expectedText += "1";
         assertEquals(expectedText, mTextView.getText().toString());
 
         // press '2' key.
-        mKeyEventUtil.sendString(mTextView, "2");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "2");
         expectedText += "2";
         assertEquals("12", mTextView.getText().toString());
 
@@ -89,35 +81,35 @@
         KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
         if ('a' == kcm.getMatch(KeyEvent.KEYCODE_A, TimeKeyListener.CHARACTERS)) {
             expectedText += "a";
-            mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_A);
+            CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_A);
             assertEquals(expectedText, mTextView.getText().toString());
         }
 
         // press 'p' key if producible
         if ('p' == kcm.getMatch(KeyEvent.KEYCODE_P, TimeKeyListener.CHARACTERS)) {
             expectedText += "p";
-            mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_P);
+            CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_P);
             assertEquals(expectedText, mTextView.getText().toString());
         }
 
         // press 'm' key if producible
         if ('m' == kcm.getMatch(KeyEvent.KEYCODE_M, TimeKeyListener.CHARACTERS)) {
             expectedText += "m";
-            mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_M);
+            CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_M);
             assertEquals(expectedText, mTextView.getText().toString());
         }
 
         // press an unaccepted key if it exists.
         int keyCode = TextMethodUtils.getUnacceptedKeyCode(TimeKeyListener.CHARACTERS);
         if (-1 != keyCode) {
-            mKeyEventUtil.sendKeys(mTextView, keyCode);
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, keyCode);
             assertEquals(expectedText, mTextView.getText().toString());
         }
 
         setKeyListenerSync(null);
 
         // press '1' key.
-        mKeyEventUtil.sendString(mTextView, "1");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "1");
         assertEquals(expectedText, mTextView.getText().toString());
     }
 
diff --git a/tests/tests/text/src/android/text/method/cts/TouchTest.java b/tests/tests/text/src/android/text/method/cts/TouchTest.java
index 233539c..cc672f9 100644
--- a/tests/tests/text/src/android/text/method/cts/TouchTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TouchTest.java
@@ -56,51 +56,33 @@
         final TextView tv = new TextViewNoIme(mActivity);
         tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(tv);
-                tv.setSingleLine(true);
-                tv.setLines(2);
-            }
+        runTestOnUiThread(() -> {
+            mActivity.setContentView(tv);
+            tv.setSingleLine(true);
+            tv.setLines(2);
         });
         getInstrumentation().waitForIdleSync();
         TextPaint paint = tv.getPaint();
         final Layout layout = tv.getLayout();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                tv.setText(LONG_TEXT);
-            }
-        });
+        runTestOnUiThread(() -> tv.setText(LONG_TEXT));
         getInstrumentation().waitForIdleSync();
 
         // get the total length of string
         final int width = getTextWidth(LONG_TEXT, paint);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Touch.scrollTo(tv, layout, width - tv.getWidth() - 1, 0);
-            }
-        });
+        runTestOnUiThread(() -> Touch.scrollTo(tv, layout, width - tv.getWidth() - 1, 0));
         getInstrumentation().waitForIdleSync();
         assertEquals(width - tv.getWidth() - 1, tv.getScrollX());
         assertEquals(0, tv.getScrollY());
 
         // the X to which scroll is greater than the total length of string.
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Touch.scrollTo(tv, layout, width + 100, 5);
-            }
-        });
+        runTestOnUiThread(() -> Touch.scrollTo(tv, layout, width + 100, 5));
         getInstrumentation().waitForIdleSync();
         assertEquals(width - tv.getWidth(), tv.getScrollX(), 1.0f);
         assertEquals(5, tv.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Touch.scrollTo(tv, layout, width - 10, 5);
-            }
-        });
+        runTestOnUiThread(() -> Touch.scrollTo(tv, layout, width - 10, 5));
         getInstrumentation().waitForIdleSync();
         assertEquals(width - tv.getWidth(), tv.getScrollX(), 1.0f);
         assertEquals(5, tv.getScrollY());
@@ -126,12 +108,10 @@
         assertTrue(dragAmount > 0);
         final String finalText = text;
         final SpannableString spannable = new SpannableString(finalText);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(tv);
-                tv.setSingleLine(true);
-                tv.setText(finalText);
-            }
+        runTestOnUiThread(() -> {
+            mActivity.setContentView(tv);
+            tv.setSingleLine(true);
+            tv.setText(finalText);
         });
         getInstrumentation().waitForIdleSync();
 
@@ -146,11 +126,7 @@
         assertEquals(0, tv.getScrollX());
         assertEquals(0, tv.getScrollY());
         mReturnFromTouchEvent = false;
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mReturnFromTouchEvent = Touch.onTouchEvent(tv, spannable, event1);
-            }
-        });
+        runTestOnUiThread(() -> mReturnFromTouchEvent = Touch.onTouchEvent(tv, spannable, event1));
         getInstrumentation().waitForIdleSync();
         assertTrue(mReturnFromTouchEvent);
         // TextView has not been scrolled.
@@ -160,11 +136,7 @@
         assertEquals(0, Touch.getInitialScrollY(tv, spannable));
 
         mReturnFromTouchEvent = false;
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mReturnFromTouchEvent = Touch.onTouchEvent(tv, spannable, event2);
-            }
-        });
+        runTestOnUiThread(() -> mReturnFromTouchEvent = Touch.onTouchEvent(tv, spannable, event2));
         getInstrumentation().waitForIdleSync();
         assertTrue(mReturnFromTouchEvent);
         // TextView has been scrolled.
@@ -174,11 +146,7 @@
         assertEquals(0, Touch.getInitialScrollY(tv, spannable));
 
         mReturnFromTouchEvent = false;
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mReturnFromTouchEvent = Touch.onTouchEvent(tv, spannable, event3);
-            }
-        });
+        runTestOnUiThread(() -> mReturnFromTouchEvent = Touch.onTouchEvent(tv, spannable, event3));
         getInstrumentation().waitForIdleSync();
         assertTrue(mReturnFromTouchEvent);
         // TextView has not been scrolled.
diff --git a/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java b/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java
index 90282b8..3c83f68 100644
--- a/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java
@@ -40,6 +40,10 @@
         new ImageSpan(b, DynamicDrawableSpan.ALIGN_BOTTOM);
         new ImageSpan(b, DynamicDrawableSpan.ALIGN_BASELINE);
 
+        new ImageSpan(mContext, b);
+        new ImageSpan(mContext, b, DynamicDrawableSpan.ALIGN_BOTTOM);
+        new ImageSpan(mContext, b, DynamicDrawableSpan.ALIGN_BASELINE);
+
         Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
         new ImageSpan(d);
         new ImageSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM);
diff --git a/tests/tests/text/src/android/text/style/cts/SuggestionSpanTest.java b/tests/tests/text/src/android/text/style/cts/SuggestionSpanTest.java
index ff5167c..86f7fe9 100644
--- a/tests/tests/text/src/android/text/style/cts/SuggestionSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/SuggestionSpanTest.java
@@ -16,16 +16,136 @@
 
 package android.text.style.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertArrayEquals;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.LocaleList;
 import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.text.style.SuggestionSpan;
 
 import java.util.Locale;
 
-public class SuggestionSpanTest extends TestCase {
+/**
+ * Test {@link SuggestionSpan}.
+ */
+public class SuggestionSpanTest extends AndroidTestCase {
+
+    @SmallTest
+    public void testConstructorWithContext() {
+        final String[] suggestions = new String[]{"suggestion1", "suggestion2"};
+        final Configuration overrideConfig = new Configuration();
+        final Locale locale = Locale.forLanguageTag("az-Arab");
+        overrideConfig.setLocales(new LocaleList(locale));
+        final Context context = getContext().createConfigurationContext(overrideConfig);
+
+        final SuggestionSpan span = new SuggestionSpan(context, suggestions,
+                SuggestionSpan.FLAG_AUTO_CORRECTION);
+
+        assertEquals(locale, span.getLocaleObject());
+        assertArrayEquals(suggestions, span.getSuggestions());
+        assertEquals(SuggestionSpan.FLAG_AUTO_CORRECTION, span.getFlags());
+    }
+
+    @SmallTest
+    public void testGetSuggestionSpans() {
+        final String[] suggestions = new String[]{"suggestion1", "suggestion2"};
+        final SuggestionSpan span = new SuggestionSpan(Locale.forLanguageTag("en"), suggestions,
+                SuggestionSpan.FLAG_AUTO_CORRECTION);
+        assertArrayEquals("Should return the correct suggestions array",
+                suggestions, span.getSuggestions());
+
+        final SuggestionSpan clonedSpan = cloneViaParcel(span);
+        assertArrayEquals("Should (de)serialize suggestions",
+                suggestions, clonedSpan.getSuggestions());
+    }
+
+    @SmallTest
+    public void testGetSuggestionSpans_emptySuggestions() {
+        final String[] suggestions = new String[0];
+        final SuggestionSpan span = new SuggestionSpan(Locale.forLanguageTag("en"), suggestions,
+                SuggestionSpan.FLAG_AUTO_CORRECTION);
+        assertArrayEquals("Span should return empty suggestion array",
+                suggestions, span.getSuggestions());
+
+        // also test parceling
+        final SuggestionSpan clonedSpan = cloneViaParcel(span);
+        assertArrayEquals("Should (de)serialize empty suggestions array",
+                suggestions, clonedSpan.getSuggestions());
+    }
+
+    @SmallTest
+    public void testGetSuggestionSpans_suggestionsWithNullValue() {
+        final String[] suggestions = new String[]{"suggestion", null};
+        final SuggestionSpan span = new SuggestionSpan(Locale.forLanguageTag("en"), suggestions,
+                SuggestionSpan.FLAG_AUTO_CORRECTION);
+        assertArrayEquals("Should accept and return null suggestions",
+                suggestions, span.getSuggestions());
+
+        final SuggestionSpan clonedSpan = cloneViaParcel(span);
+        assertArrayEquals("Should (de)serialize null in suggestions array",
+                suggestions, clonedSpan.getSuggestions());
+    }
+
+    @SmallTest
+    public void testGetFlags() {
+        final String[] anySuggestions = new String[0];
+        final int flag = SuggestionSpan.FLAG_AUTO_CORRECTION;
+        SuggestionSpan span = new SuggestionSpan(Locale.forLanguageTag("en"), anySuggestions, flag);
+
+        assertEquals("Should return the flag passed in constructor",
+                flag, span.getFlags());
+
+        final SuggestionSpan clonedSpan = cloneViaParcel(span);
+        assertEquals("Should (de)serialize flags", flag, clonedSpan.getFlags());
+    }
+
+    @SmallTest
+    public void testEquals_returnsTrueForDeserializedInstances() {
+        final SuggestionSpan span1 = new SuggestionSpan(null, Locale.forLanguageTag("en"),
+                new String[0], SuggestionSpan.FLAG_AUTO_CORRECTION, SuggestionSpan.class);
+        final SuggestionSpan span2 = cloneViaParcel(span1);
+
+        assertTrue("(De)serialized instances should be equal", span1.equals(span2));
+    }
+
+    @SmallTest
+    public void testEquals_returnsTrueIfTheFlagsAreDifferent() {
+        final SuggestionSpan span1 = new SuggestionSpan(null, Locale.forLanguageTag("en"),
+                new String[0], SuggestionSpan.FLAG_AUTO_CORRECTION, SuggestionSpan.class);
+        final SuggestionSpan span2 = cloneViaParcel(span1);
+        span2.setFlags(SuggestionSpan.FLAG_EASY_CORRECT);
+
+        assertEquals("Should return the flag passed in set function",
+                SuggestionSpan.FLAG_EASY_CORRECT, span2.getFlags());
+
+        assertTrue("Instances with different flags should be equal", span1.equals(span2));
+    }
+
+    @SmallTest
+    public void testEquals_returnsFalseIfCreationTimeIsNotSame() {
+        final Locale anyLocale = Locale.forLanguageTag("en");
+        final String[] anySuggestions = new String[0];
+        final int anyFlags = SuggestionSpan.FLAG_AUTO_CORRECTION;
+        final Class anyClass = SuggestionSpan.class;
+
+        final SuggestionSpan span1 = new SuggestionSpan(null, anyLocale, anySuggestions, anyFlags,
+                anyClass);
+        try {
+            // let some time pass before constructing the other span
+            Thread.sleep(2);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        final SuggestionSpan span2 = new SuggestionSpan(null, anyLocale, anySuggestions, anyFlags,
+                anyClass);
+
+        assertFalse("Instances created at different time should not be equal", span2.equals(span1));
+    }
 
     /**
      * @param locale a {@link Locale} object.
@@ -62,6 +182,7 @@
         assertEquals(getNonNullLocaleString(locale), cloned.getLocale());
     }
 
+    @SmallTest
     public void testGetLocaleObject() {
         checkGetLocaleObject(Locale.forLanguageTag("en"));
         checkGetLocaleObject(Locale.forLanguageTag("en-GB"));
diff --git a/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java b/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java
index c718a37..ef0b4ce 100644
--- a/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java
@@ -20,6 +20,7 @@
 import android.os.PersistableBundle;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.style.TtsSpan;
+
 import junit.framework.TestCase;
 
 public class TtsSpanTest extends TestCase {
@@ -38,7 +39,7 @@
     @SmallTest
     public void testGetArgs() {
         TtsSpan t = new TtsSpan("test.type.one", bundle);
-        PersistableBundle args = t.getArgs();
+        final PersistableBundle args = t.getArgs();
         assertEquals(4, args.size());
         assertEquals("value.one", args.getString("argument.one"));
         assertEquals("value.two", args.getString("argument.two"));
@@ -75,7 +76,7 @@
             TtsSpan t = new TtsSpan(p);
 
             assertEquals("test.type.five", t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(4, args.size());
             assertEquals("value.one", args.getString("argument.one"));
             assertEquals("value.two", args.getString("argument.two"));
@@ -88,13 +89,13 @@
 
     @SmallTest
     public void testBuilder() {
-        final TtsSpan t = (new TtsSpan.Builder<>("test.type.builder"))
+        final TtsSpan t = new TtsSpan.Builder<>("test.type.builder")
                 .setStringArgument("argument.string", "value")
                 .setIntArgument("argument.int", Integer.MAX_VALUE)
                 .setLongArgument("argument.long", Long.MAX_VALUE)
                 .build();
         assertEquals("test.type.builder", t.getType());
-        PersistableBundle args = t.getArgs();
+        final PersistableBundle args = t.getArgs();
         assertEquals(3, args.size());
         assertEquals("value", args.getString("argument.string"));
         assertEquals(Integer.MAX_VALUE, args.getInt("argument.int"));
@@ -103,14 +104,14 @@
 
     @SmallTest
     public void testSemioticClassBuilder() {
-        final TtsSpan t = (new TtsSpan.SemioticClassBuilder<>("test.type.semioticClassBuilder"))
+        final TtsSpan t = new TtsSpan.SemioticClassBuilder<>("test.type.semioticClassBuilder")
                 .setGender(TtsSpan.GENDER_FEMALE)
                 .setAnimacy(TtsSpan.ANIMACY_ANIMATE)
                 .setMultiplicity(TtsSpan.MULTIPLICITY_SINGLE)
                 .setCase(TtsSpan.CASE_NOMINATIVE)
                 .build();
         assertEquals("test.type.semioticClassBuilder", t.getType());
-        PersistableBundle args = t.getArgs();
+        final PersistableBundle args = t.getArgs();
         assertEquals(4, args.size());
         assertEquals(TtsSpan.GENDER_FEMALE, args.getString(TtsSpan.ARG_GENDER));
         assertEquals(TtsSpan.ANIMACY_ANIMATE, args.getString(TtsSpan.ARG_ANIMACY));
@@ -121,18 +122,18 @@
     @SmallTest
     public void testTextBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.TextBuilder())
+            final TtsSpan t = new TtsSpan.TextBuilder()
                     .setText("text")
                     .build();
             assertEquals(TtsSpan.TYPE_TEXT, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("text", args.getString(TtsSpan.ARG_TEXT));
         }
         {
-            final TtsSpan t = (new TtsSpan.TextBuilder("text")).build();
+            final TtsSpan t = new TtsSpan.TextBuilder("text").build();
             assertEquals(TtsSpan.TYPE_TEXT, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("text", args.getString(TtsSpan.ARG_TEXT));
         }
@@ -141,34 +142,34 @@
     @SmallTest
     public void testCardinalBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.CardinalBuilder())
+            final TtsSpan t = new TtsSpan.CardinalBuilder()
                     .setNumber(Long.MAX_VALUE)
                     .build();
             assertEquals(TtsSpan.TYPE_CARDINAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals(String.valueOf(Long.MAX_VALUE), args.getString(TtsSpan.ARG_NUMBER));
         }
         {
-            final TtsSpan t = (new TtsSpan.CardinalBuilder())
+            final TtsSpan t = new TtsSpan.CardinalBuilder()
                     .setNumber("10")
                     .build();
             assertEquals(TtsSpan.TYPE_CARDINAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
         }
         {
-            final TtsSpan t = (new TtsSpan.CardinalBuilder(Long.MAX_VALUE)).build();
+            final TtsSpan t = new TtsSpan.CardinalBuilder(Long.MAX_VALUE).build();
             assertEquals(TtsSpan.TYPE_CARDINAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals(String.valueOf(Long.MAX_VALUE), args.getString(TtsSpan.ARG_NUMBER));
         }
         {
-            final TtsSpan t = (new TtsSpan.CardinalBuilder("10")).build();
+            final TtsSpan t = new TtsSpan.CardinalBuilder("10").build();
             assertEquals(TtsSpan.TYPE_CARDINAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
         }
@@ -177,34 +178,34 @@
     @SmallTest
     public void testOrdinalBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.OrdinalBuilder())
+            final TtsSpan t = new TtsSpan.OrdinalBuilder()
                     .setNumber(Long.MAX_VALUE)
                     .build();
             assertEquals(TtsSpan.TYPE_ORDINAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals(String.valueOf(Long.MAX_VALUE), args.getString(TtsSpan.ARG_NUMBER));
         }
         {
-            final TtsSpan t = (new TtsSpan.OrdinalBuilder())
+            final TtsSpan t = new TtsSpan.OrdinalBuilder()
                     .setNumber("10")
                     .build();
             assertEquals(TtsSpan.TYPE_ORDINAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
         }
         {
-            final TtsSpan t = (new TtsSpan.OrdinalBuilder(Long.MAX_VALUE)).build();
+            final TtsSpan t = new TtsSpan.OrdinalBuilder(Long.MAX_VALUE).build();
             assertEquals(TtsSpan.TYPE_ORDINAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals(String.valueOf(Long.MAX_VALUE), args.getString(TtsSpan.ARG_NUMBER));
         }
         {
-            final TtsSpan t = (new TtsSpan.OrdinalBuilder("10")).build();
+            final TtsSpan t = new TtsSpan.OrdinalBuilder("10").build();
             assertEquals(TtsSpan.TYPE_ORDINAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
         }
@@ -213,137 +214,250 @@
     @SmallTest
     public void testDecimalBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.DecimalBuilder())
+            final TtsSpan t = new TtsSpan.DecimalBuilder()
                     .setArgumentsFromDouble(10.25, 1, 2)
                     .build();
             assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(2, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
             assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
         }
         {
-            final TtsSpan t = (new TtsSpan.DecimalBuilder(10.25, 1, 2)).build();
+            final TtsSpan t = new TtsSpan.DecimalBuilder(10.25, 1, 2).build();
             assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(2, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
             assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
         }
         {
-            final TtsSpan t = (new TtsSpan.DecimalBuilder())
+            final TtsSpan t = new TtsSpan.DecimalBuilder()
                     .setArgumentsFromDouble(10, 0, 0)
                     .build();
             assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
         }
         {
-            final TtsSpan t = (new TtsSpan.DecimalBuilder(10, 0, 0)).build();
+            final TtsSpan t = new TtsSpan.DecimalBuilder(10, 0, 0).build();
             assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
         }
         {
-            final TtsSpan t = (new TtsSpan.DecimalBuilder())
+            final TtsSpan t = new TtsSpan.DecimalBuilder()
                     .setArgumentsFromDouble(10.25, 10, 10)
                     .build();
             assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(2, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
             assertEquals("2500000000", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
         }
+        {
+            final TtsSpan t = new TtsSpan.DecimalBuilder("10", "25").build();
+            assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(2, args.size());
+            assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+            assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+        }
+        {
+            final TtsSpan t = new TtsSpan.DecimalBuilder(null, null).build();
+            assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(2, args.size());
+            assertEquals(null, args.getString(TtsSpan.ARG_INTEGER_PART));
+            assertEquals(null, args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+        }
+        {
+            final TtsSpan t = new TtsSpan.DecimalBuilder().setIntegerPart(10).build();
+            assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+        }
+        {
+            final TtsSpan t = new TtsSpan.DecimalBuilder().setIntegerPart("10").build();
+            assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+        }
+        {
+            final TtsSpan t = new TtsSpan.DecimalBuilder().setIntegerPart(null).build();
+            assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals(null, args.getString(TtsSpan.ARG_INTEGER_PART));
+        }
+        {
+            final TtsSpan t = new TtsSpan.DecimalBuilder().setFractionalPart("25").build();
+            assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+        }
+        {
+            final TtsSpan t = new TtsSpan.DecimalBuilder().setFractionalPart(null).build();
+            assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals(null, args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+        }
+        {
+            final TtsSpan t = new TtsSpan.DecimalBuilder().build();
+            assertEquals(TtsSpan.TYPE_DECIMAL, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(0, args.size());
+        }
     }
 
     @SmallTest
     public void testFractionBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.FractionBuilder())
+            final TtsSpan t = new TtsSpan.FractionBuilder()
                     .setIntegerPart(10)
                     .setNumerator(3)
                     .setDenominator(100)
                     .build();
             assertEquals(TtsSpan.TYPE_FRACTION, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(3, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
             assertEquals("3", args.getString(TtsSpan.ARG_NUMERATOR));
             assertEquals("100", args.getString(TtsSpan.ARG_DENOMINATOR));
         }
         {
-            final TtsSpan t = (new TtsSpan.FractionBuilder(10, 3, 100)).build();
+            final TtsSpan t = new TtsSpan.FractionBuilder(10, 3, 100).build();
             assertEquals(TtsSpan.TYPE_FRACTION, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(3, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
             assertEquals("3", args.getString(TtsSpan.ARG_NUMERATOR));
             assertEquals("100", args.getString(TtsSpan.ARG_DENOMINATOR));
         }
+        {
+            final TtsSpan t = new TtsSpan.FractionBuilder().setIntegerPart("10").build();
+            assertEquals(TtsSpan.TYPE_FRACTION, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+            assertEquals(null, args.getString(TtsSpan.ARG_NUMERATOR));
+            assertEquals(null, args.getString(TtsSpan.ARG_DENOMINATOR));
+        }
+        {
+            final TtsSpan t = new TtsSpan.FractionBuilder().setNumerator("3").build();
+            assertEquals(TtsSpan.TYPE_FRACTION, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("3", args.getString(TtsSpan.ARG_NUMERATOR));
+        }
+        {
+            final TtsSpan t = new TtsSpan.FractionBuilder().setDenominator("100").build();
+            assertEquals(TtsSpan.TYPE_FRACTION, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("100", args.getString(TtsSpan.ARG_DENOMINATOR));
+        }
+        {
+            final TtsSpan t = new TtsSpan.FractionBuilder().build();
+            assertEquals(TtsSpan.TYPE_FRACTION, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(0, args.size());
+        }
     }
 
     @SmallTest
     public void testMeasureBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.MeasureBuilder())
+            final TtsSpan t = new TtsSpan.MeasureBuilder()
                     .setNumber(10)
                     .setUnit("unit")
                     .build();
             assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(2, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_NUMBER));
             assertEquals("unit", args.getString(TtsSpan.ARG_UNIT));
         }
         {
-            final TtsSpan t = (new TtsSpan.MeasureBuilder())
+            final TtsSpan t = new TtsSpan.MeasureBuilder()
                     .setIntegerPart(10)
                     .setFractionalPart("25")
                     .setUnit("unit")
                     .build();
             assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(3, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
             assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
             assertEquals("unit", args.getString(TtsSpan.ARG_UNIT));
         }
         {
-            final TtsSpan t = (new TtsSpan.MeasureBuilder())
+            final TtsSpan t = new TtsSpan.MeasureBuilder()
                     .setIntegerPart(10)
                     .setNumerator(3)
                     .setDenominator(100)
                     .setUnit("unit")
                     .build();
             assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(4, args.size());
             assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
             assertEquals("3", args.getString(TtsSpan.ARG_NUMERATOR));
             assertEquals("100", args.getString(TtsSpan.ARG_DENOMINATOR));
             assertEquals("unit", args.getString(TtsSpan.ARG_UNIT));
         }
+        {
+            final TtsSpan t = new TtsSpan.MeasureBuilder().setIntegerPart("10").build();
+            assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+        }
+        {
+            final TtsSpan t = new TtsSpan.MeasureBuilder().setNumerator("3").build();
+            assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("3", args.getString(TtsSpan.ARG_NUMERATOR));
+        }
+        {
+            final TtsSpan t = new TtsSpan.MeasureBuilder().setDenominator("100").build();
+            assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("100", args.getString(TtsSpan.ARG_DENOMINATOR));
+        }
+        {
+            final TtsSpan t = new TtsSpan.MeasureBuilder().build();
+            assertEquals(TtsSpan.TYPE_MEASURE, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(0, args.size());
+        }
     }
 
     @SmallTest
     public void testTimeBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.TimeBuilder())
+            final TtsSpan t = new TtsSpan.TimeBuilder()
                     .setHours(20)
                     .setMinutes(50)
                     .build();
             assertEquals(TtsSpan.TYPE_TIME, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(2, args.size());
             assertEquals(20, args.getInt(TtsSpan.ARG_HOURS));
             assertEquals(50, args.getInt(TtsSpan.ARG_MINUTES));
         }
         {
-            final TtsSpan t = (new TtsSpan.TimeBuilder(20, 50)).build();
+            final TtsSpan t = new TtsSpan.TimeBuilder(20, 50).build();
             assertEquals(TtsSpan.TYPE_TIME, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(2, args.size());
             assertEquals(20, args.getInt(TtsSpan.ARG_HOURS));
             assertEquals(50, args.getInt(TtsSpan.ARG_MINUTES));
@@ -353,14 +467,14 @@
     @SmallTest
     public void testDateBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.DateBuilder())
+            final TtsSpan t = new TtsSpan.DateBuilder()
                     .setWeekday(3)
                     .setDay(16)
                     .setMonth(3)
                     .setYear(2016)
                     .build();
             assertEquals(TtsSpan.TYPE_DATE, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(4, args.size());
             assertEquals(3, args.getInt(TtsSpan.ARG_WEEKDAY));
             assertEquals(16, args.getInt(TtsSpan.ARG_DAY));
@@ -368,9 +482,9 @@
             assertEquals(2016, args.getInt(TtsSpan.ARG_YEAR));
         }
         {
-            final TtsSpan t = (new TtsSpan.DateBuilder(3, 16, 3, 2016)).build();
+            final TtsSpan t = new TtsSpan.DateBuilder(3, 16, 3, 2016).build();
             assertEquals(TtsSpan.TYPE_DATE, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(4, args.size());
             assertEquals(3, args.getInt(TtsSpan.ARG_WEEKDAY));
             assertEquals(16, args.getInt(TtsSpan.ARG_DAY));
@@ -378,9 +492,9 @@
             assertEquals(2016, args.getInt(TtsSpan.ARG_YEAR));
         }
         {
-            final TtsSpan t = (new TtsSpan.DateBuilder(3, 16, null, null)).build();
+            final TtsSpan t = new TtsSpan.DateBuilder(3, 16, null, null).build();
             assertEquals(TtsSpan.TYPE_DATE, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(2, args.size());
             assertEquals(3, args.getInt(TtsSpan.ARG_WEEKDAY));
             assertEquals(16, args.getInt(TtsSpan.ARG_DAY));
@@ -389,40 +503,56 @@
 
     @SmallTest
     public void testMoneyBuilder() {
-        final TtsSpan t = (new TtsSpan.MoneyBuilder())
-                .setIntegerPart(10)
-                .setFractionalPart("25")
-                .setCurrency("USD")
-                .setQuantity("1000")
-                .build();
-        assertEquals(TtsSpan.TYPE_MONEY, t.getType());
-        PersistableBundle args = t.getArgs();
-        assertEquals(4, args.size());
-        assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
-        assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
-        assertEquals("USD", args.getString(TtsSpan.ARG_CURRENCY));
-        assertEquals("1000", args.getString(TtsSpan.ARG_QUANTITY));
+        {
+            final TtsSpan t = new TtsSpan.MoneyBuilder()
+                    .setIntegerPart(10)
+                    .setFractionalPart("25")
+                    .setCurrency("USD")
+                    .setQuantity("1000")
+                    .build();
+            assertEquals(TtsSpan.TYPE_MONEY, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(4, args.size());
+            assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+            assertEquals("25", args.getString(TtsSpan.ARG_FRACTIONAL_PART));
+            assertEquals("USD", args.getString(TtsSpan.ARG_CURRENCY));
+            assertEquals("1000", args.getString(TtsSpan.ARG_QUANTITY));
+        }
+        {
+            final TtsSpan t = new TtsSpan.MoneyBuilder().setIntegerPart("10").build();
+            assertEquals(TtsSpan.TYPE_MONEY, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(1, args.size());
+            assertEquals("10", args.getString(TtsSpan.ARG_INTEGER_PART));
+        }
+        {
+            final TtsSpan t = new TtsSpan.MoneyBuilder().build();
+            assertEquals(TtsSpan.TYPE_MONEY, t.getType());
+            final PersistableBundle args = t.getArgs();
+            assertEquals(0, args.size());
+        }
+
     }
 
     @SmallTest
     public void testTelephoneBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.TelephoneBuilder())
+            final TtsSpan t = new TtsSpan.TelephoneBuilder()
                     .setCountryCode("+01")
                     .setNumberParts("000-000-0000")
                     .setExtension("0000")
                     .build();
             assertEquals(TtsSpan.TYPE_TELEPHONE, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(3, args.size());
             assertEquals("+01", args.getString(TtsSpan.ARG_COUNTRY_CODE));
             assertEquals("000-000-0000", args.getString(TtsSpan.ARG_NUMBER_PARTS));
             assertEquals("0000", args.getString(TtsSpan.ARG_EXTENSION));
         }
         {
-            final TtsSpan t = (new TtsSpan.TelephoneBuilder("000-000-0000")).build();
+            final TtsSpan t = new TtsSpan.TelephoneBuilder("000-000-0000").build();
             assertEquals(TtsSpan.TYPE_TELEPHONE, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("000-000-0000", args.getString(TtsSpan.ARG_NUMBER_PARTS));
         }
@@ -431,17 +561,17 @@
     @SmallTest
     public void testElectronicBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.ElectronicBuilder())
+            final TtsSpan t = new TtsSpan.ElectronicBuilder()
                     .setEmailArguments("example", "example.com")
                     .build();
             assertEquals(TtsSpan.TYPE_ELECTRONIC, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(2, args.size());
             assertEquals("example", args.getString(TtsSpan.ARG_USERNAME));
             assertEquals("example.com", args.getString(TtsSpan.ARG_DOMAIN));
         }
         {
-            final TtsSpan t = (new TtsSpan.ElectronicBuilder())
+            final TtsSpan t = new TtsSpan.ElectronicBuilder()
                     .setProtocol("http")
                     .setDomain("example.com")
                     .setPort(80)
@@ -452,7 +582,7 @@
                     .setPassword("password")
                     .build();
             assertEquals(TtsSpan.TYPE_ELECTRONIC, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(8, args.size());
             assertEquals("http", args.getString(TtsSpan.ARG_PROTOCOL));
             assertEquals("example.com", args.getString(TtsSpan.ARG_DOMAIN));
@@ -468,18 +598,18 @@
     @SmallTest
     public void testDigitsBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.DigitsBuilder())
+            final TtsSpan t = new TtsSpan.DigitsBuilder()
                     .setDigits("12345")
                     .build();
             assertEquals(TtsSpan.TYPE_DIGITS, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("12345", args.getString(TtsSpan.ARG_DIGITS));
         }
         {
-            final TtsSpan t = (new TtsSpan.DigitsBuilder("12345")).build();
+            final TtsSpan t = new TtsSpan.DigitsBuilder("12345").build();
             assertEquals(TtsSpan.TYPE_DIGITS, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("12345", args.getString(TtsSpan.ARG_DIGITS));
         }
@@ -488,18 +618,18 @@
     @SmallTest
     public void testVerbatimBuilder() {
         {
-            final TtsSpan t = (new TtsSpan.VerbatimBuilder())
+            final TtsSpan t = new TtsSpan.VerbatimBuilder()
                     .setVerbatim("abcdefg")
                     .build();
             assertEquals(TtsSpan.TYPE_VERBATIM, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("abcdefg", args.getString(TtsSpan.ARG_VERBATIM));
         }
         {
-            final TtsSpan t = (new TtsSpan.VerbatimBuilder("abcdefg")).build();
+            final TtsSpan t = new TtsSpan.VerbatimBuilder("abcdefg").build();
             assertEquals(TtsSpan.TYPE_VERBATIM, t.getType());
-            PersistableBundle args = t.getArgs();
+            final PersistableBundle args = t.getArgs();
             assertEquals(1, args.size());
             assertEquals("abcdefg", args.getString(TtsSpan.ARG_VERBATIM));
         }
diff --git a/tests/tests/text/src/android/text/style/cts/URLSpanTest.java b/tests/tests/text/src/android/text/style/cts/URLSpanTest.java
index 330db77..8fac2dd 100644
--- a/tests/tests/text/src/android/text/style/cts/URLSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/URLSpanTest.java
@@ -16,20 +16,18 @@
 
 package android.text.style.cts;
 
-import android.text.cts.R;
-
-
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.Instrumentation.ActivityMonitor;
 import android.os.Parcel;
 import android.test.ActivityInstrumentationTestCase2;
+import android.text.cts.R;
 import android.text.style.URLSpan;
 import android.widget.TextView;
 
 public class URLSpanTest extends ActivityInstrumentationTestCase2<URLSpanCtsActivity> {
-    // The scheme of TEST_URL must be "ctstest" to launch MockURLSpanTestActivity
-    private static final String TEST_URL = "ctstest://urlSpan/test";
+    // The scheme of TEST_URL must be "ctstesttext" to launch MockURLSpanTestActivity
+    private static final String TEST_URL = "ctstesttext://urlSpan/test";
     private Activity mActivity;
 
     public URLSpanTest() {
@@ -69,11 +67,7 @@
                 null, false);
 
         try {
-            runTestOnUiThread(new Runnable() {
-                public void run() {
-                    urlSpan.onClick(textView);
-                }
-            });
+            runTestOnUiThread(() -> urlSpan.onClick(textView));
         } catch (Throwable e) {
             fail("Exception error!");
         }
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 a159da9..431c754 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -592,13 +592,6 @@
     }
 
     @SmallTest
-    public void testAddLinks_partiallyMatchesUrlWithInvalidRequestParameter() throws Exception {
-        String url = "http://android.com?p=value";
-        assertAddLinksWithWebUrlPartiallyMatches("Should partially match URL with invalid " +
-                "request parameter", "http://android.com", url);
-    }
-
-    @SmallTest
     public void testAddLinks_matchesValidUrlWithEmoji() throws Exception {
         String url = "Thank\u263A.com";
         assertAddLinksWithWebUrlSucceeds("Should match URL with emoji", url);
@@ -669,6 +662,48 @@
         }
     }
 
+    @SmallTest
+    public void testAddLinks_matchesDomainNameWithDash() throws Exception {
+        String url = "http://a-nd.r-oid.com";
+        assertAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+
+        url = "a-nd.r-oid.com";
+        assertAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+    }
+
+    @SmallTest
+    public void testAddLinks_matchesDomainNameWithUnderscore() throws Exception {
+        String url = "http://a_nd.r_oid.com";
+        assertAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+
+        url = "a_nd.r_oid.com";
+        assertAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+    }
+
+    @SmallTest
+    public void testAddLinks_matchesPathAndQueryWithDollarSign() throws Exception {
+        String url = "http://android.com/path$?v=$val";
+        assertAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+
+        url = "android.com/path$?v=$val";
+        assertAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+    }
+
+    @SmallTest
+    public void testAddLinks_matchesEmptyPathWithQueryParams() throws Exception {
+        String url = "http://android.com?q=v";
+        assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+        url = "android.com?q=v";
+        assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+        url = "http://android.com/?q=v";
+        assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+        url = "android.com/?q=v";
+        assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+    }
+
     // EMAIL_ADDRESSES Related Tests
 
     public void testAddLinks_email_matchesShortValidEmail() throws Exception {
diff --git a/tests/tests/text/src/android/text/util/cts/Rfc822TokenizerTest.java b/tests/tests/text/src/android/text/util/cts/Rfc822TokenizerTest.java
index 4d145f1..b3aa714 100644
--- a/tests/tests/text/src/android/text/util/cts/Rfc822TokenizerTest.java
+++ b/tests/tests/text/src/android/text/util/cts/Rfc822TokenizerTest.java
@@ -18,17 +18,24 @@
 
 
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.text.util.Rfc822Token;
 import android.text.util.Rfc822Tokenizer;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Test {@link Rfc822Tokenizer}.
  */
 public class Rfc822TokenizerTest extends AndroidTestCase {
+
+    @SmallTest
     public void testConstructor() {
         new Rfc822Tokenizer();
     }
 
+    @SmallTest
     public void testFindTokenStart() {
         Rfc822Tokenizer rfc822Tokenizer = new Rfc822Tokenizer();
 
@@ -61,6 +68,7 @@
         }
     }
 
+    @SmallTest
     public void testFindTokenEnd() {
         Rfc822Tokenizer rfc822Tokenizer = new Rfc822Tokenizer();
 
@@ -96,6 +104,7 @@
         }
     }
 
+    @SmallTest
     public void testTerminateToken() {
         Rfc822Tokenizer rfc822Tokenizer = new Rfc822Tokenizer();
 
@@ -110,21 +119,22 @@
         assertEquals(text + comma + space, rfc822Tokenizer.terminateToken(null));
     }
 
+    @SmallTest
     public void testTokenize() {
         Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("");
         assertEquals(0, tokens.length);
 
-        String text = "\"Berg\" (home) <berg\\@google.com>, tom\\@google.com (work)";
+        String text = "\"Berg\" (home) <berg\\@example.com>, tom\\@example.com (work)";
         tokens = Rfc822Tokenizer.tokenize(text);
         assertEquals(2, tokens.length);
-        localAssertEquals(tokens[0], "Berg", "berg\\@google.com", "home");
-        localAssertEquals(tokens[1], null, "tom\\@google.com", "work");
+        localAssertEquals(tokens[0], "Berg", "berg\\@example.com", "home");
+        localAssertEquals(tokens[1], null, "tom\\@example.com", "work");
 
-        text = "Foo Bar (something) <foo\\@google.com>, blah\\@google.com (something)";
+        text = "Foo Bar (something) <foo\\@example.com>, blah\\@example.com (something)";
         tokens = Rfc822Tokenizer.tokenize(text);
         assertEquals(2, tokens.length);
-        localAssertEquals(tokens[0], "Foo Bar", "foo\\@google.com", "something");
-        localAssertEquals(tokens[1], null, "blah\\@google.com", "something");
+        localAssertEquals(tokens[0], "Foo Bar", "foo\\@example.com", "something");
+        localAssertEquals(tokens[1], null, "blah\\@example.com", "something");
 
         try {
             Rfc822Tokenizer.tokenize(null);
@@ -134,6 +144,32 @@
         }
     }
 
+    @SmallTest
+    public void testTokenize_withListParam() {
+        final List<Rfc822Token> list = new ArrayList<>();
+        Rfc822Tokenizer.tokenize("", list);
+        assertEquals(0, list.size());
+
+        String text = "\"Berg\" (home) <berg\\@example.com>, tom\\@example.com (work)";
+        Rfc822Tokenizer.tokenize(text, list);
+        assertEquals(2, list.size());
+        localAssertEquals(list.get(0), "Berg", "berg\\@example.com", "home");
+        localAssertEquals(list.get(1), null, "tom\\@example.com", "work");
+
+        text = "Foo Bar (something) <foo\\@example.com>, blah\\@example.com (something)";
+        list.clear();
+        Rfc822Tokenizer.tokenize(text, list);
+        assertEquals(2, list.size());
+        localAssertEquals(list.get(0), "Foo Bar", "foo\\@example.com", "something");
+        localAssertEquals(list.get(1), null, "blah\\@example.com", "something");
+
+        try {
+            Rfc822Tokenizer.tokenize(null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+        }
+    }
+
     /**
      * Assert the specified token's name, address and comment all equal specified ones.
      * @param token the Rfc822Token to be asserted.
diff --git a/tests/tests/transition/Android.mk b/tests/tests/transition/Android.mk
index af8b4eb..5370d4f 100644
--- a/tests/tests/transition/Android.mk
+++ b/tests/tests/transition/Android.mk
@@ -24,13 +24,19 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES += \
+    android-support-test \
+    mockito-target \
+    android-common \
+    ctsdeviceutil \
+    ctstestrunner \
+    platform-test-annotations
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-LOCAL_SDK_VERSION := current
-
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/transition/res/layout/scene11.xml b/tests/tests/transition/res/layout/scene11.xml
new file mode 100644
index 0000000..8ecad8d
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene11.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:transitionName="holder"
+                android:id="@+id/holder">
+    <ImageView
+        android:id="@+id/redSquare"
+        android:src="#F00"
+        android:layout_width="10dp"
+        android:layout_height="10dp"/>
+</RelativeLayout>
diff --git a/tests/tests/transition/res/transition/arc_motion.xml b/tests/tests/transition/res/transition/arc_motion.xml
new file mode 100644
index 0000000..264f074
--- /dev/null
+++ b/tests/tests/transition/res/transition/arc_motion.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android">
+    <arcMotion android:minimumVerticalAngle="1"
+               android:minimumHorizontalAngle="2"
+               android:maximumAngle="53"/>
+</changeBounds>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/auto_transition.xml b/tests/tests/transition/res/transition/auto_transition.xml
new file mode 100644
index 0000000..e285105
--- /dev/null
+++ b/tests/tests/transition/res/transition/auto_transition.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<autoTransition/>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/change_bounds.xml b/tests/tests/transition/res/transition/change_bounds.xml
new file mode 100644
index 0000000..162372c
--- /dev/null
+++ b/tests/tests/transition/res/transition/change_bounds.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android"
+      android:resizeClip="true"/>
diff --git a/tests/tests/transition/res/transition/change_clip_bounds.xml b/tests/tests/transition/res/transition/change_clip_bounds.xml
new file mode 100644
index 0000000..70a7dc6
--- /dev/null
+++ b/tests/tests/transition/res/transition/change_clip_bounds.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<changeClipBounds/>
diff --git a/tests/tests/transition/res/transition/change_image_transform.xml b/tests/tests/transition/res/transition/change_image_transform.xml
new file mode 100644
index 0000000..b37ab04
--- /dev/null
+++ b/tests/tests/transition/res/transition/change_image_transform.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<changeImageTransform/>
diff --git a/tests/tests/transition/res/transition/change_scroll.xml b/tests/tests/transition/res/transition/change_scroll.xml
new file mode 100644
index 0000000..9054686
--- /dev/null
+++ b/tests/tests/transition/res/transition/change_scroll.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<changeScroll/>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/change_transform.xml b/tests/tests/transition/res/transition/change_transform.xml
new file mode 100644
index 0000000..c87c549
--- /dev/null
+++ b/tests/tests/transition/res/transition/change_transform.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+<changeTransform xmlns:android="http://schemas.android.com/apk/res/android"
+    android:reparent="false" android:reparentWithOverlay="false"/>
diff --git a/tests/tests/transition/res/transition/custom_path_motion.xml b/tests/tests/transition/res/transition/custom_path_motion.xml
new file mode 100644
index 0000000..1704419
--- /dev/null
+++ b/tests/tests/transition/res/transition/custom_path_motion.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android">
+    <pathMotion class="android.transition.cts.TransitionInflaterTest$CustomPathMotion"/>
+</changeBounds>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/custom_transition.xml b/tests/tests/transition/res/transition/custom_transition.xml
new file mode 100644
index 0000000..35ee285
--- /dev/null
+++ b/tests/tests/transition/res/transition/custom_transition.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<transition class="android.transition.cts.TransitionInflaterTest$CustomTransition"/>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/explode.xml b/tests/tests/transition/res/transition/explode.xml
new file mode 100644
index 0000000..a038d8b
--- /dev/null
+++ b/tests/tests/transition/res/transition/explode.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+<explode xmlns:android="http://schemas.android.com/apk/res/android"
+    android:transitionVisibilityMode="mode_in"/>
diff --git a/tests/tests/transition/res/transition/fade.xml b/tests/tests/transition/res/transition/fade.xml
new file mode 100644
index 0000000..2057014
--- /dev/null
+++ b/tests/tests/transition/res/transition/fade.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+<fade xmlns:android="http://schemas.android.com/apk/res/android"
+      android:fadingMode="fade_out"/>
diff --git a/tests/tests/transition/res/transition/pattern_path_motion.xml b/tests/tests/transition/res/transition/pattern_path_motion.xml
new file mode 100644
index 0000000..f794447
--- /dev/null
+++ b/tests/tests/transition/res/transition/pattern_path_motion.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android">
+    <patternPathMotion android:patternPathData="M0 0 L0 100 L100 100"/>
+</changeBounds>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/slide.xml b/tests/tests/transition/res/transition/slide.xml
new file mode 100644
index 0000000..9fde010
--- /dev/null
+++ b/tests/tests/transition/res/transition/slide.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+<slide xmlns:android="http://schemas.android.com/apk/res/android"
+    android:slideEdge="top"/>
diff --git a/tests/tests/transition/res/transition/target_classes.xml b/tests/tests/transition/res/transition/target_classes.xml
new file mode 100644
index 0000000..01d1e2d
--- /dev/null
+++ b/tests/tests/transition/res/transition/target_classes.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android">
+    <targets>
+        <target android:targetClass="android.widget.TextView"/>
+        <target android:targetClass="android.widget.ImageView"/>
+    </targets>
+</changeBounds>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/target_ids.xml b/tests/tests/transition/res/transition/target_ids.xml
new file mode 100644
index 0000000..2340e46
--- /dev/null
+++ b/tests/tests/transition/res/transition/target_ids.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android">
+    <targets>
+        <target android:targetId="@+id/hello"/>
+        <target android:targetId="@+id/world"/>
+    </targets>
+</changeBounds>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/target_names.xml b/tests/tests/transition/res/transition/target_names.xml
new file mode 100644
index 0000000..b90cf19
--- /dev/null
+++ b/tests/tests/transition/res/transition/target_names.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<changeBounds xmlns:android="http://schemas.android.com/apk/res/android">
+    <targets>
+        <target android:targetName="hello"/>
+        <target android:targetName="world"/>
+    </targets>
+</changeBounds>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/transition_constructors.xml b/tests/tests/transition/res/transition/transition_constructors.xml
new file mode 100644
index 0000000..e442187
--- /dev/null
+++ b/tests/tests/transition/res/transition/transition_constructors.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationFade"/>
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationChangeBounds"/>
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationChangeImageTransform"/>
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationChangeTransform"/>
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationAutoTransition"/>
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationChangeClipBounds"/>
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationChangeScroll"/>
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationExplode"/>
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationSlide"/>
+    <transition class="android.transition.cts.TransitionInflaterTest$InflationTransitionSet"/>
+</transitionSet>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/transition_manager.xml b/tests/tests/transition/res/transition/transition_manager.xml
new file mode 100644
index 0000000..8d3186c
--- /dev/null
+++ b/tests/tests/transition/res/transition/transition_manager.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
+    <transition android:toScene="@layout/scene1"
+                android:transition="@transition/fade"/>
+    <transition android:fromScene="@layout/scene1" android:toScene="@layout/scene2"
+                android:transition="@transition/change_bounds"/>
+</transitionManager>
\ No newline at end of file
diff --git a/tests/tests/transition/res/transition/transition_set.xml b/tests/tests/transition/res/transition/transition_set.xml
new file mode 100644
index 0000000..3b1ff3c
--- /dev/null
+++ b/tests/tests/transition/res/transition/transition_set.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
+    android:transitionOrdering="sequential">
+    <changeBounds/>
+    <fade/>
+</transitionSet>
diff --git a/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
index 944ff91..a5da03e 100644
--- a/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
@@ -89,7 +89,7 @@
     }
 
     protected Scene loadScene(final View layout) throws Throwable {
-        Scene[] scene = new Scene[1];
+        final Scene[] scene = new Scene[1];
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -101,7 +101,7 @@
     }
 
     protected Scene loadScene(final int layoutId) throws Throwable {
-        Scene scene[] = new Scene[1];
+        final Scene scene[] = new Scene[1];
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
diff --git a/tests/tests/transition/src/android/transition/cts/CaptureValuesTest.java b/tests/tests/transition/src/android/transition/cts/CaptureValuesTest.java
new file mode 100644
index 0000000..84b154a
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/CaptureValuesTest.java
@@ -0,0 +1,246 @@
+/*
+ * 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.transition.cts;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.transition.AutoTransition;
+import android.transition.ChangeBounds;
+import android.transition.ChangeClipBounds;
+import android.transition.ChangeImageTransform;
+import android.transition.ChangeScroll;
+import android.transition.ChangeTransform;
+import android.transition.Explode;
+import android.transition.Fade;
+import android.transition.Slide;
+import android.transition.Transition;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.transition.TransitionValues;
+import android.util.ArrayMap;
+
+@MediumTest
+public class CaptureValuesTest extends BaseTransitionTest {
+    private ArrayMap<Class<?>, Boolean> mStartCaptured = new ArrayMap<>();
+    private ArrayMap<Class<?>, Boolean> mEndCaptured = new ArrayMap<>();
+
+    /**
+     * Ensures captureValues is called on all Transitions and the proper values are captured.
+     */
+    public void testCaptureValues() throws Throwable {
+        final TransitionSetCaptureValues set = new TransitionSetCaptureValues();
+        set.addTransition(new FadeCaptureValues());
+        set.addTransition(new ChangeBoundsCaptureValues());
+        set.addTransition(new ChangeImageTransformCaptureValues());
+        set.addTransition(new ChangeTransformCaptureValues());
+        set.addTransition(new AutoTransitionCaptureValues());
+        set.addTransition(new ChangeClipBoundsCaptureValues());
+        set.addTransition(new ChangeScrollCaptureValues());
+        set.addTransition(new ExplodeCaptureValues());
+        set.addTransition(new SlideCaptureValues());
+
+        enterScene(R.layout.scene11);
+        set.addTarget(getActivity().findViewById(R.id.redSquare));
+        mTransition = set;
+        resetListener();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.beginDelayedTransition(mSceneRoot, set);
+                mSceneRoot.invalidate();
+            }
+        });
+        waitForStart();
+        // no transition needs to run, but they should have all captured values.
+
+        for (int i = 0; i < set.getTransitionCount(); i++) {
+            Transition transition = set.getTransitionAt(i);
+            String className = transition.getClass().getSuperclass().getSimpleName().toString();
+            assertNotNull("captureStartValues not called for " + className,
+                    mStartCaptured.get(transition.getClass()));
+            assertNotNull("captureEndValues not called for " + className,
+                    mEndCaptured.get(transition.getClass()));
+        }
+        assertNotNull(mStartCaptured.get(set.getClass()));
+        assertNotNull(mEndCaptured.get(set.getClass()));
+    }
+
+    private void testCapturedValues(Transition transition, TransitionValues values,
+            boolean isStart) {
+        String[] properties = transition.getTransitionProperties();
+        if (transition instanceof TransitionSet) {
+            assertNull(properties);
+        } else {
+            String className = transition.getClass().getSuperclass().getSimpleName().toString();
+            assertNotNull(className + " should have non-null transition properties", properties);
+            assertTrue(properties.length > 0);
+
+            for (String property : properties) {
+                assertTrue(className + " should have written to property " + property,
+                        values.values.keySet().contains(property));
+            }
+        }
+        if (isStart) {
+            mStartCaptured.put(transition.getClass(), true);
+        } else {
+            mEndCaptured.put(transition.getClass(), true);
+        }
+    }
+
+    public class FadeCaptureValues extends Fade {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeBoundsCaptureValues extends ChangeBounds {
+        public ChangeBoundsCaptureValues() {
+            super();
+            setResizeClip(true);
+            setReparent(true);
+        }
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeImageTransformCaptureValues extends ChangeImageTransform {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeTransformCaptureValues extends ChangeTransform {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class AutoTransitionCaptureValues extends AutoTransition {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeClipBoundsCaptureValues extends ChangeClipBounds {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeScrollCaptureValues extends ChangeScroll {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ExplodeCaptureValues extends Explode {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class SlideCaptureValues extends Slide {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+    public class TransitionSetCaptureValues extends TransitionSet {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            testCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            testCapturedValues(this, transitionValues, false);
+        }
+    }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/PatternPathMotionTest.java b/tests/tests/transition/src/android/transition/cts/PatternPathMotionTest.java
index 5485b4a..6655213 100644
--- a/tests/tests/transition/src/android/transition/cts/PatternPathMotionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/PatternPathMotionTest.java
@@ -47,5 +47,14 @@
 
         assertPathMatches(expected, pathMotion.getPath(0, 0, 0, 100));
     }
+
+    public void testSetPatternPath() throws Throwable {
+        Path pattern = new Path();
+        pattern.addArc(0, 0, 100, 100, 0, 180);
+
+        PatternPathMotion patternPathMotion = new PatternPathMotion();
+        patternPathMotion.setPatternPath(pattern);
+        assertSame(pattern, patternPathMotion.getPatternPath());
+    }
 }
 
diff --git a/tests/tests/transition/src/android/transition/cts/PropagationTest.java b/tests/tests/transition/src/android/transition/cts/PropagationTest.java
new file mode 100644
index 0000000..7b49c15
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/PropagationTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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.transition.cts;
+
+import android.graphics.Rect;
+import android.transition.CircularPropagation;
+import android.transition.SidePropagation;
+import android.transition.Transition;
+import android.transition.TransitionValues;
+import android.view.Gravity;
+import android.view.View;
+
+public class PropagationTest extends BaseTransitionTest {
+    public void testCircularPropagation() throws Throwable {
+        enterScene(R.layout.scene10);
+        CircularPropagation propagation = new CircularPropagation();
+        mTransition.setPropagation(propagation);
+        final TransitionValues redValues = new TransitionValues();
+        redValues.view = getActivity().findViewById(R.id.redSquare);
+        propagation.captureValues(redValues);
+
+        // Only the reported propagation properties are set
+        for (String prop : propagation.getPropagationProperties()) {
+            assertTrue(redValues.values.keySet().contains(prop));
+        }
+        assertEquals(propagation.getPropagationProperties().length, redValues.values.size());
+
+        // check the visibility
+        assertEquals(View.VISIBLE, propagation.getViewVisibility(redValues));
+        assertEquals(View.GONE, propagation.getViewVisibility(null));
+
+        // Check the positions
+        int[] pos = new int[2];
+        redValues.view.getLocationOnScreen(pos);
+        pos[0] += redValues.view.getWidth() / 2;
+        pos[1] += redValues.view.getHeight() / 2;
+        assertEquals(pos[0], propagation.getViewX(redValues));
+        assertEquals(pos[1], propagation.getViewY(redValues));
+
+        mTransition.setEpicenterCallback(new Transition.EpicenterCallback() {
+            @Override
+            public Rect onGetEpicenter(Transition transition) {
+                return new Rect(0, 0, redValues.view.getWidth(), redValues.view.getHeight());
+            }
+        });
+
+        long redDelay = getDelay(R.id.redSquare);
+        // red square's delay should be roughly 0 since it is at the epicenter
+        assertEquals(0f, redDelay, 30f);
+
+        // The green square is on the upper-right
+        long greenDelay = getDelay(R.id.greenSquare);
+        assertTrue(greenDelay < redDelay);
+
+        // The blue square is on the lower-right
+        long blueDelay = getDelay(R.id.blueSquare);
+        assertTrue(blueDelay < greenDelay);
+
+        // Test propagation speed
+        propagation.setPropagationSpeed(1000000000f);
+        assertEquals(0, getDelay(R.id.blueSquare));
+    }
+
+    public void testSidePropagationBottom() throws Throwable {
+        SidePropagation propagation = new SidePropagation();
+        propagation.setSide(Gravity.BOTTOM);
+        mTransition.setEpicenterCallback(new Transition.EpicenterCallback() {
+            @Override
+            public Rect onGetEpicenter(Transition transition) {
+                return new Rect(0, 0, 1, 1);
+            }
+        });
+        mTransition.setPropagation(propagation);
+
+        enterScene(R.layout.scene10);
+
+        // The red square is on the upper-left
+        long redDelay = getDelay(R.id.redSquare);
+
+        // The green square is on the upper-right
+        long greenDelay = getDelay(R.id.greenSquare);
+
+        // The blue square is on the lower-right
+        long blueDelay = getDelay(R.id.blueSquare);
+
+        // The yellow square is on the lower-left
+        long yellowDelay = getDelay(R.id.yellowSquare);
+
+        assertTrue(redDelay > greenDelay);
+        assertTrue(redDelay > yellowDelay);
+        assertTrue(greenDelay > blueDelay);
+        assertTrue(yellowDelay > blueDelay);
+
+        // Test propagation speed
+        propagation.setPropagationSpeed(1000000000f);
+        assertEquals(0, getDelay(R.id.blueSquare));
+    }
+
+    public void testSidePropagationTop() throws Throwable {
+        SidePropagation propagation = new SidePropagation();
+        propagation.setSide(Gravity.TOP);
+        mTransition.setEpicenterCallback(new Transition.EpicenterCallback() {
+            @Override
+            public Rect onGetEpicenter(Transition transition) {
+                return new Rect(0, 0, 1, 1);
+            }
+        });
+        mTransition.setPropagation(propagation);
+
+        enterScene(R.layout.scene10);
+
+        // The red square is on the upper-left
+        long redDelay = getDelay(R.id.redSquare);
+
+        // The green square is on the upper-right
+        long greenDelay = getDelay(R.id.greenSquare);
+
+        // The blue square is on the lower-right
+        long blueDelay = getDelay(R.id.blueSquare);
+
+        // The yellow square is on the lower-left
+        long yellowDelay = getDelay(R.id.yellowSquare);
+
+        assertTrue(yellowDelay > redDelay);
+        assertTrue(yellowDelay > blueDelay);
+        assertTrue(redDelay > greenDelay);
+        assertTrue(blueDelay > greenDelay);
+    }
+
+    public void testSidePropagationRight() throws Throwable {
+        SidePropagation propagation = new SidePropagation();
+        propagation.setSide(Gravity.RIGHT);
+        mTransition.setEpicenterCallback(new Transition.EpicenterCallback() {
+            @Override
+            public Rect onGetEpicenter(Transition transition) {
+                return new Rect(0, 0, 1, 1);
+            }
+        });
+        mTransition.setPropagation(propagation);
+
+        enterScene(R.layout.scene10);
+
+        // The red square is on the upper-left
+        long redDelay = getDelay(R.id.redSquare);
+
+        // The green square is on the upper-right
+        long greenDelay = getDelay(R.id.greenSquare);
+
+        // The blue square is on the lower-right
+        long blueDelay = getDelay(R.id.blueSquare);
+
+        // The yellow square is on the lower-left
+        long yellowDelay = getDelay(R.id.yellowSquare);
+
+        assertTrue(redDelay > greenDelay);
+        assertTrue(redDelay > yellowDelay);
+        assertTrue(yellowDelay > blueDelay);
+        assertTrue(greenDelay > blueDelay);
+    }
+
+    public void testSidePropagationLeft() throws Throwable {
+        SidePropagation propagation = new SidePropagation();
+        propagation.setSide(Gravity.LEFT);
+        mTransition.setEpicenterCallback(new Transition.EpicenterCallback() {
+            @Override
+            public Rect onGetEpicenter(Transition transition) {
+                return new Rect(0, 0, 1, 1);
+            }
+        });
+        mTransition.setPropagation(propagation);
+
+        enterScene(R.layout.scene10);
+
+        // The red square is on the upper-left
+        long redDelay = getDelay(R.id.redSquare);
+
+        // The green square is on the upper-right
+        long greenDelay = getDelay(R.id.greenSquare);
+
+        // The blue square is on the lower-right
+        long blueDelay = getDelay(R.id.blueSquare);
+
+        // The yellow square is on the lower-left
+        long yellowDelay = getDelay(R.id.yellowSquare);
+
+        assertTrue(greenDelay > redDelay);
+        assertTrue(greenDelay > blueDelay);
+        assertTrue(redDelay > yellowDelay);
+        assertTrue(blueDelay > yellowDelay);
+    }
+
+    private TransitionValues capturePropagationValues(int viewId) {
+        TransitionValues transitionValues = new TransitionValues();
+        transitionValues.view = mSceneRoot.findViewById(viewId);
+        mTransition.getPropagation().captureValues(transitionValues);
+        return transitionValues;
+    }
+
+    private long getDelay(int viewId) {
+        TransitionValues transitionValues = capturePropagationValues(viewId);
+        return mTransition.getPropagation().
+                getStartDelay(mSceneRoot, mTransition, transitionValues, null);
+    }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/SceneTest.java b/tests/tests/transition/src/android/transition/cts/SceneTest.java
index 2785714..48fb6c1 100644
--- a/tests/tests/transition/src/android/transition/cts/SceneTest.java
+++ b/tests/tests/transition/src/android/transition/cts/SceneTest.java
@@ -17,12 +17,12 @@
 
 import android.transition.Scene;
 import android.view.View;
+import android.view.ViewGroup;
 
 public class SceneTest extends BaseTransitionTest {
-
-    public SceneTest() {
-    }
-
+    /**
+     * Test Scene(ViewGroup) with enterAction and exitAction
+     */
     public void testDynamicConstructor() throws Throwable {
         Scene scene = new Scene(mSceneRoot);
         assertEquals(mSceneRoot, scene.getSceneRoot());
@@ -52,32 +52,34 @@
         assertNull(mSceneRoot.findViewById(R.id.redSquare));
     }
 
+    /**
+     * Test Scene(ViewGroup, View)
+     */
     public void testViewConstructor() throws Throwable {
         View view = loadLayout(R.layout.scene1);
-        Scene scene = new Scene(mSceneRoot, view);
-        assertEquals(mSceneRoot, scene.getSceneRoot());
-        CallCheck enterCheck = new CallCheck();
-        scene.setEnterAction(enterCheck);
-        CallCheck exitCheck = new CallCheck();
-        scene.setExitAction(exitCheck);
-        enterScene(scene);
-
-        assertTrue(enterCheck.wasRun);
-        assertFalse(exitCheck.wasRun);
-
-        View redSquare = mActivity.findViewById(R.id.redSquare);
-        assertNotNull(redSquare);
-
-        exitScene(scene);
-        assertNotNull(mSceneRoot.findViewById(R.id.redSquare));
-        assertTrue(exitCheck.wasRun);
-
-        enterScene(R.layout.scene4);
-        assertNull(mSceneRoot.findViewById(R.id.redSquare));
+        constructorTest(new Scene(mSceneRoot, view));
     }
 
+    /**
+     * Test Scene(ViewGroup, ViewGroup)
+     */
+    public void testDeprecatedConstructor() throws Throwable {
+        View view = loadLayout(R.layout.scene1);
+        constructorTest(new Scene(mSceneRoot, (ViewGroup) view));
+    }
+
+    /**
+     * Test Scene.getSceneForLayout
+     */
     public void testFactory() throws Throwable {
         Scene scene = loadScene(R.layout.scene1);
+        constructorTest(scene);
+    }
+
+    /**
+     * Tests that the Scene was constructed properly from a scene1
+     */
+    private void constructorTest(Scene scene) throws Throwable {
         assertEquals(mSceneRoot, scene.getSceneRoot());
         CallCheck enterCheck = new CallCheck();
         scene.setEnterAction(enterCheck);
@@ -94,8 +96,6 @@
         exitScene(scene);
         assertNotNull(mSceneRoot.findViewById(R.id.redSquare));
         assertTrue(exitCheck.wasRun);
-        enterScene(R.layout.scene4);
-        assertNull(mSceneRoot.findViewById(R.id.redSquare));
     }
 
     private static class CallCheck implements Runnable {
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionInflaterTest.java b/tests/tests/transition/src/android/transition/cts/TransitionInflaterTest.java
new file mode 100644
index 0000000..22c0616
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/TransitionInflaterTest.java
@@ -0,0 +1,308 @@
+/*
+ * 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.transition.cts;
+
+import android.content.Context;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.support.test.filters.MediumTest;
+import android.transition.ArcMotion;
+import android.transition.AutoTransition;
+import android.transition.ChangeBounds;
+import android.transition.ChangeClipBounds;
+import android.transition.ChangeImageTransform;
+import android.transition.ChangeScroll;
+import android.transition.ChangeTransform;
+import android.transition.Explode;
+import android.transition.Fade;
+import android.transition.PathMotion;
+import android.transition.PatternPathMotion;
+import android.transition.Scene;
+import android.transition.Slide;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.transition.TransitionValues;
+import android.transition.Visibility;
+import android.transition.cts.R;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.List;
+
+@MediumTest
+public class TransitionInflaterTest extends BaseTransitionTest {
+    public void testInflationConstructors() throws Throwable {
+        TransitionInflater inflater = TransitionInflater.from(mActivity);
+        Transition transition = inflater.inflateTransition(R.transition.transition_constructors);
+        assertTrue(transition instanceof TransitionSet);
+        TransitionSet set = (TransitionSet) transition;
+        assertEquals(10, set.getTransitionCount());
+    }
+
+    public void testInflation() {
+        TransitionInflater inflater = TransitionInflater.from(mActivity);
+        assureFadeProperties(inflater.inflateTransition(R.transition.fade));
+        assureChangeBoundsProperties(inflater.inflateTransition(R.transition.change_bounds));
+        assureSlideProperties(inflater.inflateTransition(R.transition.slide));
+        assureExplodeProperties(inflater.inflateTransition(R.transition.explode));
+        assureChangeImageTransformProperties(
+                inflater.inflateTransition(R.transition.change_image_transform));
+        assureChangeTransformProperties(inflater.inflateTransition(R.transition.change_transform));
+        assureChangeClipBoundsProperties(
+                inflater.inflateTransition(R.transition.change_clip_bounds));
+        assureAutoTransitionProperties(inflater.inflateTransition(R.transition.auto_transition));
+        assureChangeScrollProperties(inflater.inflateTransition(R.transition.change_scroll));
+        assureTransitionSetProperties(inflater.inflateTransition(R.transition.transition_set));
+        assureCustomTransitionProperties(
+                inflater.inflateTransition(R.transition.custom_transition));
+        testTargetIds(inflater.inflateTransition(R.transition.target_ids));
+        testTargetNames(inflater.inflateTransition(R.transition.target_names));
+        testTargetClass(inflater.inflateTransition(R.transition.target_classes));
+        testArcMotion(inflater.inflateTransition(R.transition.arc_motion));
+        testCustomPathMotion(inflater.inflateTransition(R.transition.custom_path_motion));
+        testPatternPathMotion(inflater.inflateTransition(R.transition.pattern_path_motion));
+    }
+
+    public void testInflateTransitionManager() throws Throwable {
+        TransitionInflater inflater = TransitionInflater.from(mActivity);
+        TransitionManager transitionManager =
+                inflater.inflateTransitionManager(R.transition.transition_manager, mSceneRoot);
+        assertNotNull(transitionManager);
+
+        Scene scene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
+        Transition transition = transitionManager.getTransition(scene1);
+        assertNotNull(transition);
+        assertTrue(transition instanceof Fade);
+        enterScene(scene1);
+
+        Scene scene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
+        transition = transitionManager.getTransition(scene2);
+        assertNotNull(transition);
+        assertTrue(transition instanceof ChangeBounds);
+    }
+
+    private void assureFadeProperties(Transition transition) {
+        assertTrue(transition instanceof Fade);
+        Fade fade = (Fade) transition;
+        assertEquals(Fade.OUT, fade.getMode());
+    }
+
+    private void assureChangeBoundsProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeBounds);
+        ChangeBounds changeBounds = (ChangeBounds) transition;
+        assertTrue(changeBounds.getResizeClip());
+    }
+
+    private void assureSlideProperties(Transition transition) {
+        assertTrue(transition instanceof Slide);
+        Slide slide = (Slide) transition;
+        assertEquals(Gravity.TOP, slide.getSlideEdge());
+    }
+
+    private void assureExplodeProperties(Transition transition) {
+        assertTrue(transition instanceof Explode);
+        Visibility visibility = (Visibility) transition;
+        assertEquals(Visibility.MODE_IN, visibility.getMode());
+    }
+
+    private void assureChangeImageTransformProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeImageTransform);
+    }
+
+    private void assureChangeTransformProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeTransform);
+        ChangeTransform changeTransform = (ChangeTransform) transition;
+        assertFalse(changeTransform.getReparent());
+        assertFalse(changeTransform.getReparentWithOverlay());
+    }
+
+    private void assureChangeClipBoundsProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeClipBounds);
+    }
+
+    private void assureAutoTransitionProperties(Transition transition) {
+        assertTrue(transition instanceof AutoTransition);
+    }
+
+    private void assureChangeScrollProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeScroll);
+    }
+
+    private void assureTransitionSetProperties(Transition transition) {
+        assertTrue(transition instanceof TransitionSet);
+        TransitionSet set = (TransitionSet) transition;
+        assertEquals(TransitionSet.ORDERING_SEQUENTIAL, set.getOrdering());
+        assertEquals(2, set.getTransitionCount());
+        assertTrue(set.getTransitionAt(0) instanceof ChangeBounds);
+        assertTrue(set.getTransitionAt(1) instanceof Fade);
+    }
+
+    private void assureCustomTransitionProperties(Transition transition) {
+        assertTrue(transition instanceof CustomTransition);
+    }
+
+    private void testTargetIds(Transition transition) {
+        List<Integer> targets = transition.getTargetIds();
+        assertNotNull(targets);
+        assertEquals(2, targets.size());
+        assertEquals(R.id.hello, (int) targets.get(0));
+        assertEquals(R.id.world, (int) targets.get(1));
+    }
+
+    private void testTargetNames(Transition transition) {
+        List<String> targets = transition.getTargetNames();
+        assertNotNull(targets);
+        assertEquals(2, targets.size());
+        assertEquals("hello", targets.get(0));
+        assertEquals("world", targets.get(1));
+    }
+
+    private void testTargetClass(Transition transition) {
+        List<Class> targets = transition.getTargetTypes();
+        assertNotNull(targets);
+        assertEquals(2, targets.size());
+        assertEquals(TextView.class, targets.get(0));
+        assertEquals(ImageView.class, targets.get(1));
+    }
+
+    private void testArcMotion(Transition transition) {
+        assertNotNull(transition);
+        PathMotion motion = transition.getPathMotion();
+        assertNotNull(motion);
+        assertTrue(motion instanceof ArcMotion);
+        ArcMotion arcMotion = (ArcMotion) motion;
+        assertEquals(1f, arcMotion.getMinimumVerticalAngle(), 0.01f);
+        assertEquals(2f, arcMotion.getMinimumHorizontalAngle(), 0.01f);
+        assertEquals(53f, arcMotion.getMaximumAngle(), 0.01f);
+    }
+
+    private void testCustomPathMotion(Transition transition) {
+        assertNotNull(transition);
+        PathMotion motion = transition.getPathMotion();
+        assertNotNull(motion);
+        assertTrue(motion instanceof CustomPathMotion);
+    }
+
+    private void testPatternPathMotion(Transition transition) {
+        assertNotNull(transition);
+        PathMotion motion = transition.getPathMotion();
+        assertNotNull(motion);
+        assertTrue(motion instanceof PatternPathMotion);
+        PatternPathMotion pattern = (PatternPathMotion) motion;
+        Path path = pattern.getPatternPath();
+        PathMeasure measure = new PathMeasure(path, false);
+        assertEquals(200f, measure.getLength(), 0.1f);
+    }
+
+    public static class CustomTransition extends Transition {
+        public CustomTransition() {
+            fail("Default constructor was not expected");
+        }
+
+        public CustomTransition(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+
+        }
+    }
+
+    public static class CustomPathMotion extends PathMotion {
+        public CustomPathMotion() {
+            fail("default constructor shouldn't be called.");
+        }
+
+        public CustomPathMotion(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @Override
+        public Path getPath(float startX, float startY, float endX, float endY) {
+            return null;
+        }
+    }
+
+    public static class InflationFade extends Fade {
+        public InflationFade(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationChangeBounds extends ChangeBounds {
+        public InflationChangeBounds(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationSlide extends Slide {
+        public InflationSlide(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationTransitionSet extends TransitionSet {
+        public InflationTransitionSet(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationChangeImageTransform extends ChangeImageTransform {
+        public InflationChangeImageTransform(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationChangeTransform extends ChangeTransform {
+        public InflationChangeTransform(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationAutoTransition extends AutoTransition {
+        public InflationAutoTransition(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationChangeClipBounds extends ChangeClipBounds {
+        public InflationChangeClipBounds(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationChangeScroll extends ChangeScroll {
+        public InflationChangeScroll(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+
+    public static class InflationExplode extends Explode {
+        public InflationExplode(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
index 9eacd1b..a8a653d 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
@@ -15,11 +15,13 @@
  */
 package android.transition.cts;
 
+import android.graphics.Rect;
 import android.transition.cts.R;
 
 import android.transition.Scene;
 import android.transition.TransitionManager;
 import android.view.View;
+import android.view.ViewTreeObserver;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -57,6 +59,49 @@
         });
     }
 
+    public void testDefaultBeginDelayedTransition() throws Throwable {
+        enterScene(R.layout.scene1);
+        final CountDownLatch startLatch = new CountDownLatch(1);
+        mSceneRoot.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+                        startLatch.countDown();
+                        return true;
+                    }
+                });
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.beginDelayedTransition(mSceneRoot);
+            }
+        });
+        enterScene(R.layout.scene6);
+        assertTrue(startLatch.await(500, TimeUnit.MILLISECONDS));
+        ensureRedSquareIsMoving();
+        endTransition();
+    }
+
+    private void ensureRedSquareIsMoving() throws InterruptedException {
+        final View view = getActivity().findViewById(R.id.redSquare);
+        assertNotNull(view);
+        // We should see a ChangeBounds on redSquare
+        final Rect position = new Rect(view.getLeft(), view.getTop(), view.getRight(),
+                view.getBottom());
+        final CountDownLatch latch = new CountDownLatch(1);
+        view.postOnAnimationDelayed(new Runnable() {
+            @Override
+            public void run() {
+                Rect next = new Rect(view.getLeft(), view.getTop(), view.getRight(),
+                        view.getBottom());
+                assertTrue(!next.equals(position));
+                latch.countDown();
+            }
+        }, 20);
+        assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
+    }
+
     public void testGo() throws Throwable {
         startTransition(R.layout.scene1);
         waitForStart();
@@ -77,6 +122,30 @@
         });
     }
 
+    public void testDefaultGo() throws Throwable {
+        enterScene(R.layout.scene1);
+        final CountDownLatch startLatch = new CountDownLatch(1);
+        mSceneRoot.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+                        startLatch.countDown();
+                        return true;
+                    }
+                });
+        final Scene scene6 = loadScene(R.layout.scene6);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.go(scene6);
+            }
+        });
+        assertTrue(startLatch.await(500, TimeUnit.MILLISECONDS));
+        ensureRedSquareIsMoving();
+        endTransition();
+    }
+
     public void testSetTransition1() throws Throwable {
         final TransitionManager transitionManager = new TransitionManager();
 
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionTest.java b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
index 9ae568a..71b22fe 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
@@ -23,6 +23,7 @@
 import android.transition.ArcMotion;
 import android.transition.AutoTransition;
 import android.transition.ChangeBounds;
+import android.transition.CircularPropagation;
 import android.transition.PathMotion;
 import android.transition.Scene;
 import android.transition.Transition;
@@ -240,6 +241,7 @@
     public void testIsTransitionRequired() throws Throwable {
         enterScene(R.layout.scene1);
         mTransition = new NotRequiredTransition();
+        assertFalse(mTransition.isTransitionRequired(null, null));
         resetListener();
         runTestOnUiThread(new Runnable() {
             @Override
@@ -315,6 +317,19 @@
         endTransition();
     }
 
+    public void testExcludeChildrenClass() throws Throwable {
+        enterScene(R.layout.scene1);
+        mTransition.excludeChildren(RelativeLayout.class, true);
+        startTransition(R.layout.scene2);
+        waitForEnd(0); // Should already be ended, since no children are transitioning
+
+        resetListener();
+        mTransition.excludeChildren(RelativeLayout.class, false); // remove it
+        startTransition(R.layout.scene1);
+        assertEquals(1, mListener.endLatch.getCount()); // It is running
+        endTransition();
+    }
+
     public void testExcludeTargetView() throws Throwable {
         View layout1 = loadLayout(R.layout.scene1);
         Scene scene1 = loadScene(layout1);
@@ -383,6 +398,7 @@
     }
 
     public void testEpicenter() throws Throwable {
+        assertNull(mTransition.getEpicenter());
         EpicenterCallback callback = new EpicenterCallback() {
             @Override
             public Rect onGetEpicenter(Transition transition) {
@@ -390,7 +406,8 @@
             }
         };
         mTransition.setEpicenterCallback(callback);
-        assertEquals(callback, mTransition.getEpicenterCallback());
+        assertSame(callback, mTransition.getEpicenterCallback());
+        assertEquals(new Rect(0, 0, 1, 1), mTransition.getEpicenter());
     }
 
     public void testInterpolator() throws Throwable {
@@ -467,6 +484,14 @@
         endTransition();
     }
 
+    public void testSetPropagation() throws Throwable {
+        Transition transition = new ChangeBounds();
+        assertNull(transition.getPropagation());
+        TransitionPropagation propagation = new CircularPropagation();
+        transition.setPropagation(propagation);
+        assertSame(propagation, transition.getPropagation());
+    }
+
     public void testStartDelay() throws Throwable {
         CaptureAnimatorTransition transition = new CaptureAnimatorTransition();
         mTransition = transition;
@@ -489,10 +514,13 @@
 
     public void testTransitionValues() throws Throwable {
         enterScene(R.layout.scene1);
-        mTransition = new CheckTransitionValuesTransition();
+        CheckTransitionValuesTransition transition = new CheckTransitionValuesTransition();
+        mTransition = transition;
         mTransition.setDuration(10);
         resetListener();
-        startTransition(R.layout.scene4);
+        startTransition(R.layout.scene2);
+        assertTrue(transition.onDisappearCalled.await(500, TimeUnit.MILLISECONDS));
+        assertTrue(transition.onAppearCalled.await(500, TimeUnit.MILLISECONDS));
         // The transition has all the asserts in it, so we can just end it now.
         endTransition();
     }
@@ -515,6 +543,29 @@
         waitForEnd(400);
     }
 
+    public void testGetTransitionProperties() throws Throwable {
+        enterScene(R.layout.scene1);
+        // Make the transition make changes to properties in getTransitionProperties.
+        TransitionPropertiesTransition transition = new TransitionPropertiesTransition(false);
+        mTransition = transition;
+        resetListener();
+        startTransition(R.layout.scene2);
+        assertTrue(transition.latch.await(500, TimeUnit.MILLISECONDS));
+        endTransition();
+
+        // Now make the transition only make changes to unimportant properties.
+        transition = new TransitionPropertiesTransition(true);
+        mTransition = transition;
+        resetListener();
+        startTransition(R.layout.scene1);
+        assertTrue(mListener.endLatch.await(500, TimeUnit.MILLISECONDS));
+        // createAnimator shouldn't have been called.
+        assertEquals(1, transition.latch.getCount());
+
+        assertNotNull(transition.getTransitionProperties());
+        assertEquals(1, transition.getTransitionProperties().length);
+    }
+
     private class NotRequiredTransition extends TestTransition {
         @Override
         public boolean isTransitionRequired(TransitionValues startValues,
@@ -551,9 +602,12 @@
     }
 
     private class CheckTransitionValuesTransition extends TestTransition {
+        public CountDownLatch onAppearCalled = new CountDownLatch(1);
+        public CountDownLatch onDisappearCalled = new CountDownLatch(1);
         @Override
         public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
                 TransitionValues endValues) {
+            onAppearCalled.countDown();
             assertNull(getTransitionValues(endValues.view, true));
             assertEquals(endValues, getTransitionValues(endValues.view, false));
             return super.onAppear(sceneRoot, view, startValues, endValues);
@@ -562,6 +616,7 @@
         @Override
         public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
                 TransitionValues endValues) {
+            onDisappearCalled.countDown();
             assertNull(getTransitionValues(startValues.view, false));
             assertEquals(startValues, getTransitionValues(startValues.view, true));
             return super.onDisappear(sceneRoot, view, startValues, endValues);
@@ -576,5 +631,48 @@
             startLatch.countDown();
         }
     }
+
+    private static class TransitionPropertiesTransition extends Transition {
+        private static final String SIDE_PROP = "prop1";
+        private static final String IMPORTANT_PROP = "prop2";
+        private static final String[] PROPERTIES = {
+                IMPORTANT_PROP
+        };
+
+        private boolean mOnlyUnimportant;
+        public CountDownLatch latch = new CountDownLatch(1);
+
+        public TransitionPropertiesTransition(boolean onlyUnimportant) {
+            mOnlyUnimportant = onlyUnimportant;
+        }
+
+        @Override
+        public String[] getTransitionProperties() {
+            return PROPERTIES;
+        }
+
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            transitionValues.values.put(SIDE_PROP, 1);
+            transitionValues.values.put(IMPORTANT_PROP, 1);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            transitionValues.values.put(SIDE_PROP, 2);
+            int val = mOnlyUnimportant ? 1 : 2;
+            transitionValues.values.put(IMPORTANT_PROP, val);
+        }
+
+        @Override
+        public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+                TransitionValues endValues) {
+            if (startValues != null && endValues != null) {
+                latch.countDown();
+            }
+
+            return null;
+        }
+    }
 }
 
diff --git a/tests/tests/transition/src/android/transition/cts/VisibilityTest.java b/tests/tests/transition/src/android/transition/cts/VisibilityTest.java
index 9b91a36..81977a4 100644
--- a/tests/tests/transition/src/android/transition/cts/VisibilityTest.java
+++ b/tests/tests/transition/src/android/transition/cts/VisibilityTest.java
@@ -15,9 +15,15 @@
  */
 package android.transition.cts;
 
+import android.animation.Animator;
+import android.transition.TransitionManager;
 import android.transition.TransitionValues;
 import android.transition.Visibility;
 import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 public class VisibilityTest extends BaseTransitionTest {
     Visibility mVisibilityTransition;
@@ -104,5 +110,102 @@
         mTransition.captureStartValues(goneValues);
         assertFalse(mVisibilityTransition.isVisible(goneValues));
     }
+
+    public void testOnAppear() throws Throwable {
+        enterScene(R.layout.scene4);
+        AppearTransition transition = new AppearTransition();
+        mTransition = transition;
+        resetListener();
+        startTransition(R.layout.scene5);
+        assertTrue(transition.onAppearCalled.await(500, TimeUnit.MILLISECONDS));
+        // No need to end the transition since AppearTransition doesn't create
+        // any animators.
+    }
+
+    public void testOnDisppear() throws Throwable {
+        // First, test with overlay
+        enterScene(R.layout.scene5);
+        DisappearTransition transition = new DisappearTransition(true);
+        mTransition = transition;
+        resetListener();
+        startTransition(R.layout.scene4);
+        assertTrue(transition.onDisppearCalled.await(500, TimeUnit.MILLISECONDS));
+        // No need to end the transition since DisappearTransition doesn't create
+        // any animators.
+
+        // Next test without overlay
+        enterScene(R.layout.scene5);
+        transition = new DisappearTransition(false);
+        mTransition = transition;
+        resetListener();
+        final View text = getActivity().findViewById(R.id.text);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+                text.setVisibility(View.GONE);
+            }
+        });
+        assertTrue(transition.onDisppearCalled.await(500, TimeUnit.MILLISECONDS));
+        // No need to end the transition since DisappearTransition doesn't create
+        // any animators.
+    }
+
+    static class AppearTransition extends Visibility {
+        private View mExpectedView;
+        public CountDownLatch onAppearCalled = new CountDownLatch(1);
+        @Override
+        public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues,
+                int startVisibility, TransitionValues endValues, int endVisibility) {
+            assertNotNull(endValues);
+            mExpectedView = endValues.view;
+            return super.onAppear(sceneRoot, startValues, startVisibility, endValues,
+                    endVisibility);
+        }
+
+        @Override
+        public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+                TransitionValues endValues) {
+            assertSame(mExpectedView, view);
+            onAppearCalled.countDown();
+            return null;
+        }
+    }
+
+    static class DisappearTransition extends Visibility {
+        private View mExpectedView;
+        private final boolean mExpectingOverlay;
+        public CountDownLatch onDisppearCalled = new CountDownLatch(1);
+
+        public DisappearTransition(boolean expectingOverlay) {
+            mExpectingOverlay = expectingOverlay;
+        }
+
+        @Override
+        public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
+                int startVisibility, TransitionValues endValues, int endVisibility) {
+            assertNotNull(startValues);
+            if (mExpectingOverlay) {
+                assertNull(endValues);
+                mExpectedView = null;
+            } else {
+                assertNotNull(endValues);
+                mExpectedView = endValues.view;
+            }
+            return super.onDisappear(sceneRoot, startValues, startVisibility, endValues,
+                    endVisibility);
+        }
+
+        @Override
+        public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+                TransitionValues endValues) {
+            assertNotNull(view);
+            if (mExpectedView != null) {
+                assertSame(mExpectedView, view);
+            }
+            onDisppearCalled.countDown();
+            return null;
+        }
+    }
 }
 
diff --git a/tests/tests/uirendering/Android.mk b/tests/tests/uirendering/Android.mk
index fd01e10..2aeea5e 100644
--- a/tests/tests/uirendering/Android.mk
+++ b/tests/tests/uirendering/Android.mk
@@ -26,7 +26,10 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ctstestrunner \
+    mockito-target \
+    android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
 
diff --git a/tests/tests/uirendering/AndroidManifest.xml b/tests/tests/uirendering/AndroidManifest.xml
index 24cdd8a..41ec318 100644
--- a/tests/tests/uirendering/AndroidManifest.xml
+++ b/tests/tests/uirendering/AndroidManifest.xml
@@ -21,9 +21,11 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <application>
-<!--            android:theme="@style/WhiteBackgroundTheme"> -->
         <activity android:name="android.uirendering.cts.testinfrastructure.DrawActivity"
                 android:theme="@style/WhiteBackgroundTheme"></activity>
+        <activity android:name="android.uirendering.cts.testinfrastructure.MaterialActivity"
+                android:theme="@android:style/Theme.Material.Light">
+        </activity>
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/tests/tests/uirendering/res/drawable-nodpi/edge_effect_color.png b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_color.png
new file mode 100644
index 0000000..7ca4067
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_color.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/edge_effect_displacement_0.png b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_displacement_0.png
new file mode 100644
index 0000000..e315dfd
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_displacement_0.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/edge_effect_displacement_1.png b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_displacement_1.png
new file mode 100644
index 0000000..5e719b2
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_displacement_1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/edge_effect_green.png b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_green.png
new file mode 100644
index 0000000..321250b
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_green.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/edge_effect_red.png b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_red.png
new file mode 100644
index 0000000..6429808
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_red.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/edge_effect_size.png b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_size.png
new file mode 100644
index 0000000..d2af211
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/edge_effect_size.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/golden_blue_circle.png b/tests/tests/uirendering/res/drawable-nodpi/golden_blue_circle.png
new file mode 100644
index 0000000..f587fb7
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/golden_blue_circle.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/golden_dashed_oval.png b/tests/tests/uirendering/res/drawable-nodpi/golden_dashed_oval.png
new file mode 100644
index 0000000..c95568a
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/golden_dashed_oval.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/text_on_path.png b/tests/tests/uirendering/res/drawable-nodpi/text_on_path.png
new file mode 100644
index 0000000..d0dee6c
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/text_on_path.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable/dashed_oval.xml b/tests/tests/uirendering/res/drawable/dashed_oval.xml
new file mode 100644
index 0000000..904b016
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable/dashed_oval.xml
@@ -0,0 +1,25 @@
+<?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.
+  -->
+<shape
+    android:shape="oval"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <stroke
+        android:width="2px"
+        android:dashGap="6px"
+        android:dashWidth="2px"
+        android:color="@android:color/black"
+        />
+</shape>
diff --git a/tests/tests/uirendering/res/layout/frame_layout.xml b/tests/tests/uirendering/res/layout/frame_layout.xml
index 0eb1f9b..4ceac5d 100644
--- a/tests/tests/uirendering/res/layout/frame_layout.xml
+++ b/tests/tests/uirendering/res/layout/frame_layout.xml
@@ -17,4 +17,3 @@
     android:id="@+id/frame_layout"
     android:layout_width="@dimen/test_width"
     android:layout_height="@dimen/test_height"/>
-
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java
index 42e8960..b9816db 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java
@@ -15,7 +15,9 @@
  */
 package android.uirendering.cts.bitmapverifiers;
 
+import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.differencevisualizers.PassFailVisualizer;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -31,6 +33,10 @@
         mBitmapComparer = bitmapComparer;
     }
 
+    public GoldenImageVerifier(Context context, int goldenResId, BitmapComparer bitmapComparer) {
+        this(BitmapFactory.decodeResource(context.getResources(), goldenResId), bitmapComparer);
+    }
+
     @Override
     public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
         boolean success = mBitmapComparer.verifySame(mGoldenBitmapArray, bitmap, offset, stride,
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
index 1e7a832..8360948 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
@@ -16,12 +16,18 @@
 
 package android.uirendering.cts.testclasses;
 
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.util.DisplayMetrics;
+
 import org.junit.Test;
 
 import static org.junit.Assert.assertFalse;
@@ -114,4 +120,68 @@
                 })
                 .runWithoutVerification();
     }
+
+    private void testFailureOnBitmapDraw(Bitmap bitmap) {
+        createTest()
+                .addCanvasClient((canvas, width, height) -> {
+                    boolean sawException = false;
+                    try {
+                        canvas.drawBitmap(bitmap, 0, 0, null);
+                    } catch (RuntimeException e) {
+                        sawException = true;
+                    }
+                    assertTrue(sawException);
+                })
+                .runWithoutVerification();
+    }
+
+    @Test
+    public void testFailureOnDrawRecycledBitmap() {
+        Bitmap recycledBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+        recycledBitmap.recycle();
+        testFailureOnBitmapDraw(recycledBitmap);
+    }
+
+    @Test
+    public void testFailureOnNonPremultipliedBitmap() {
+        Bitmap nonPremultipliedBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+        nonPremultipliedBitmap.setPremultiplied(false);
+        nonPremultipliedBitmap.setHasAlpha(true);
+        testFailureOnBitmapDraw(nonPremultipliedBitmap);
+    }
+
+    @Test
+    public void testDrawScreenWideBitmap() {
+        createTest()
+                .addCanvasClient((canvas, width, height) -> {
+                    DisplayMetrics displayMetrics =
+                            getActivity().getResources().getDisplayMetrics();
+                    assertTrue(displayMetrics.widthPixels <= canvas.getMaximumBitmapWidth());
+                    assertTrue(displayMetrics.heightPixels <= canvas.getMaximumBitmapHeight());
+                    Bitmap bitmap = Bitmap.createBitmap(displayMetrics.widthPixels,
+                            displayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
+                    bitmap.eraseColor(Color.RED);
+                    canvas.drawBitmap(bitmap, 0, 0, null);
+                })
+                .runWithVerifier(new ColorVerifier(Color.RED, 0));
+    }
+
+    @Test
+    public void testDrawLargeBitmap() {
+        // verify that HW and SW pipelines can both draw screen-and-a-half sized bitmap
+        createTest()
+                .addCanvasClient((canvas, width, height) -> {
+                    DisplayMetrics displayMetrics =
+                            getActivity().getResources().getDisplayMetrics();
+
+                    int bWidth = displayMetrics.widthPixels * 3 / 2;
+                    int bHeight = displayMetrics.heightPixels * 3 / 2;
+                    bWidth = Math.min(bWidth, canvas.getMaximumBitmapWidth());
+                    bHeight = Math.min(bHeight, canvas.getMaximumBitmapHeight());
+                    Bitmap bitmap = Bitmap.createBitmap(bWidth, bHeight, Bitmap.Config.ARGB_8888);
+                    bitmap.eraseColor(Color.RED);
+                    canvas.drawBitmap(bitmap, 0, 0, null);
+                })
+                .runWithVerifier(new ColorVerifier(Color.RED, 0));
+    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
new file mode 100644
index 0000000..a5137af
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
@@ -0,0 +1,214 @@
+/*
+ * 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.assertTrue;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
+import android.uirendering.cts.testinfrastructure.MaterialActivity;
+import android.uirendering.cts.util.BitmapAsserter;
+import android.widget.EdgeEffect;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class EdgeEffectTests {
+
+    private static final int WIDTH = 90;
+    private static final int HEIGHT = 90;
+
+    @Rule
+    public TestName name = new TestName();
+
+    @Rule
+    public ActivityTestRule<MaterialActivity> mActivityRule = new ActivityTestRule<>(
+            MaterialActivity.class);
+
+    private BitmapAsserter mBitmapAsserter = new BitmapAsserter(this.getClass().getSimpleName(),
+            name.getMethodName());
+
+    interface EdgeEffectInitializer {
+        void initialize(EdgeEffect edgeEffect);
+    }
+
+    private Activity getActivity() {
+        return mActivityRule.getActivity();
+    }
+
+    @Before
+    public void setUp() {
+        mBitmapAsserter.setUp(getActivity());
+    }
+
+    private void assertEdgeEffect(EdgeEffectInitializer initializer, int goldenId) {
+        Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        canvas.drawColor(Color.WHITE);
+        EdgeEffect edgeEffect = new EdgeEffect(getActivity());
+        edgeEffect.setSize(WIDTH, HEIGHT);
+        edgeEffect.setColor(Color.RED);
+        initializer.initialize(edgeEffect);
+        edgeEffect.draw(canvas);
+
+        GoldenImageVerifier verifier = new GoldenImageVerifier(getActivity(), goldenId,
+                new MSSIMComparer(0.99));
+        mBitmapAsserter.assertBitmapIsVerified(bitmap, verifier,
+                name.getMethodName(), "EdgeEffect doesn't match expected");
+    }
+
+    @Test
+    public void testOnPull() {
+        assertEdgeEffect(edgeEffect -> {
+            edgeEffect.onPull(1);
+        }, R.drawable.edge_effect_red);
+    }
+
+    @Test
+    public void testSetSize() {
+        assertEdgeEffect(edgeEffect -> {
+            edgeEffect.setSize(70, 70);
+            edgeEffect.onPull(1);
+        }, R.drawable.edge_effect_size);
+    }
+
+    @Test
+    public void testSetColor() {
+        assertEdgeEffect(edgeEffect -> {
+            edgeEffect.setColor(Color.GREEN);
+            edgeEffect.onPull(1);
+        }, R.drawable.edge_effect_green);
+    }
+
+    @Test
+    public void testOnPullWithDisplacement() {
+        assertEdgeEffect(edgeEffect -> {
+            edgeEffect.onPull(1, 0);
+        }, R.drawable.edge_effect_displacement_0);
+
+        assertEdgeEffect(edgeEffect -> {
+            edgeEffect.onPull(1, 1);
+        }, R.drawable.edge_effect_displacement_1);
+    }
+
+    @Test
+    public void testIsFinished() {
+        EdgeEffect effect = new EdgeEffect(getActivity());
+        assertTrue(effect.isFinished());
+        effect.onPull(0.5f);
+        assertFalse(effect.isFinished());
+    }
+
+    @Test
+    public void testFinish() {
+        EdgeEffect effect = new EdgeEffect(getActivity());
+        effect.onPull(1);
+        effect.finish();
+        assertTrue(effect.isFinished());
+
+        effect.onAbsorb(1000);
+        effect.finish();
+        assertFalse(effect.draw(new Canvas()));
+    }
+
+    @Test
+    public void testGetColor() {
+        EdgeEffect effect = new EdgeEffect(getActivity());
+        effect.setColor(Color.GREEN);
+        assertEquals(Color.GREEN, effect.getColor());
+    }
+
+    @Test
+    public void testGetMaxHeight() {
+        EdgeEffect edgeEffect = new EdgeEffect(getActivity());
+        edgeEffect.setSize(200, 200);
+        assertTrue(edgeEffect.getMaxHeight() <= 200 * 2 + 1);
+        edgeEffect.setSize(200, 0);
+        assertEquals(0, edgeEffect.getMaxHeight());
+    }
+
+    private interface AlphaVerifier {
+        void verify(int oldAlpha, int newAlpha);
+    }
+
+    // validates changes to the alpha of draw commands produced by EdgeEffect
+    // over the course of an animation
+    private void verifyAlpha(EdgeEffectInitializer initializer, AlphaVerifier alphaVerifier) {
+        Canvas canvas = mock(Canvas.class);
+        ArgumentCaptor<Paint> captor = ArgumentCaptor.forClass(Paint.class);
+        EdgeEffect edgeEffect = new EdgeEffect(getActivity());
+        edgeEffect.setSize(200, 200);
+        initializer.initialize(edgeEffect);
+        edgeEffect.draw(canvas);
+        verify(canvas).drawCircle(anyFloat(), anyFloat(), anyFloat(), captor.capture());
+        int oldAlpha = captor.getValue().getAlpha();
+        for (int i = 0; i < 3; i++) {
+            try {
+                Thread.sleep(20);
+            } catch (InterruptedException e) {
+                fail();
+            }
+            canvas = mock(Canvas.class);
+            edgeEffect.draw(canvas);
+            verify(canvas).drawCircle(anyFloat(), anyFloat(), anyFloat(), captor.capture());
+            int newAlpha = captor.getValue().getAlpha();
+            alphaVerifier.verify(oldAlpha, newAlpha);
+            oldAlpha = newAlpha;
+        }
+    }
+
+    @Test
+    public void testOnAbsorb() {
+        verifyAlpha(edgeEffect -> {
+            edgeEffect.onAbsorb(10000);
+        }, ((oldAlpha, newAlpha) -> {
+            assertTrue("Alpha should grow", oldAlpha < newAlpha);
+        }));
+    }
+
+    @Test
+    public void testOnRelease() {
+        verifyAlpha(edgeEffect -> {
+            edgeEffect.onPull(1);
+            edgeEffect.onRelease();
+        }, ((oldAlpha, newAlpha) -> {
+            assertTrue("Alpha should decrease", oldAlpha > newAlpha);
+        }));
+    }
+
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index 6f90433..d0bfbf2 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -16,8 +16,11 @@
 
 package android.uirendering.cts.testclasses;
 
+import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Picture;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.NinePatchDrawable;
@@ -26,6 +29,8 @@
 import android.uirendering.cts.bitmapcomparers.ExactComparer;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.R;
 import org.junit.Test;
@@ -138,6 +143,44 @@
                 .runWithComparer(mExactComparer);
     }
 
+    private void drawTestTextOnPath(Canvas canvas) {
+        final String testString = "THIS IS A TEST ON A CIRCLE PATH";
+        Path path = new Path();
+        path.addCircle(45, 45, 30, Path.Direction.CW);
+        Paint p = new Paint();
+        p.setColor(Color.BLACK);
+        p.setAntiAlias(true);
+        canvas.drawTextOnPath(testString, path, 0f, 0f, p);
+    }
+
+    @Test
+    public void testTextOnPath() {
+        createTest()
+                .addCanvasClient((canvas, width, height) -> {
+                    drawTestTextOnPath(canvas);
+                })
+                .runWithVerifier(new GoldenImageVerifier(getActivity(),
+                    // HWUI's texts are blurry, so we lower the threshold.
+                    // Note that 0.7 will fail the test.
+                    R.drawable.text_on_path, new MSSIMComparer(0.6)));
+    }
+
+    @Test
+    public void testTextOnPathUsingPicture() {
+        createTest()
+                .addCanvasClient((canvas, width, height) -> {
+                    Picture picture = new Picture();
+                    Canvas pictureCanvas = picture.beginRecording(90, 90);
+                    drawTestTextOnPath(pictureCanvas);
+                    picture.endRecording();
+                    picture.draw(canvas);
+                })
+                .runWithVerifier(new GoldenImageVerifier(getActivity(),
+                    // HWUI's texts are blurry, so we lower the threshold.
+                    // Note that 0.7 will fail the test.
+                    R.drawable.text_on_path, new MSSIMComparer(0.6)));
+    }
+
     @Test
     public void testBasicColorXfermode() {
         createTest()
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
new file mode 100644
index 0000000..18fd2bc
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
@@ -0,0 +1,37 @@
+/*
+ * 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 android.graphics.*;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import org.junit.Test;
+
+@MediumTest
+public class ShapeTests extends ActivityTestBase {
+    @Test
+    public void testDashedOval() {
+        createTest()
+                .addLayout(R.layout.frame_layout,
+                        view -> view.setBackgroundResource(R.drawable.dashed_oval))
+                .runWithVerifier(new GoldenImageVerifier(getActivity(),
+                        R.drawable.golden_dashed_oval, new MSSIMComparer(0.99)));
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java
new file mode 100644
index 0000000..4a3e7cf
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java
@@ -0,0 +1,41 @@
+/*
+ * 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 android.test.suitebuilder.annotation.MediumTest;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.ViewInitializer;
+import android.view.ViewAnimationUtils;
+import org.junit.Test;
+
+@MediumTest
+public class ViewAnimationUtilsTests extends ActivityTestBase {
+    @Test
+    public void testCreateCircularReveal() {
+        createTest()
+                .addLayout(R.layout.blue_padded_layout, (ViewInitializer) view -> {
+                    ViewAnimationUtils.createCircularReveal(view, 45, 45, 45, 45)
+                            .setDuration(10000) // 10 sec, longer than animation
+                            .start();
+                }, true)
+                .runWithVerifier(new GoldenImageVerifier(getActivity(),
+                        R.drawable.golden_blue_circle, new MSSIMComparer(0.99)));
+    }
+}
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 458f69b..b983a48 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -19,14 +19,10 @@
 import android.app.Instrumentation;
 import android.graphics.Bitmap;
 import android.graphics.Point;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
 import android.support.test.rule.ActivityTestRule;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
-import android.uirendering.cts.differencevisualizers.DifferenceVisualizer;
-import android.uirendering.cts.differencevisualizers.PassFailVisualizer;
-import android.uirendering.cts.util.BitmapDumper;
+import android.uirendering.cts.util.BitmapAsserter;
 import android.util.Log;
 
 import android.support.test.InstrumentationRegistry;
@@ -40,8 +36,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import static org.junit.Assert.assertTrue;
-
 /**
  * This class contains the basis for the graphics hardware test classes. Contained within this class
  * are several methods that help with the execution of tests, and should be extended to gain the
@@ -50,16 +44,11 @@
 public abstract class ActivityTestBase {
     public static final String TAG = "ActivityTestBase";
     public static final boolean DEBUG = false;
-    public static final boolean USE_RS = false;
 
     //The minimum height and width of a device
     public static final int TEST_WIDTH = 90;
     public static final int TEST_HEIGHT = 90;
 
-    private int[] mHardwareArray = new int[TEST_HEIGHT * TEST_WIDTH];
-    private int[] mSoftwareArray = new int[TEST_HEIGHT * TEST_WIDTH];
-    private DifferenceVisualizer mDifferenceVisualizer;
-    private RenderScript mRenderScript;
     private TestCaseBuilder mTestCaseBuilder;
 
     @Rule
@@ -69,21 +58,8 @@
     @Rule
     public TestName name = new TestName();
 
-    /**
-     * The default constructor creates the package name and sets the DrawActivity as the class that
-     * we would use.
-     */
-    public ActivityTestBase() {
-        mDifferenceVisualizer = new PassFailVisualizer();
-
-        // Create a location for the files to be held, if it doesn't exist already
-        BitmapDumper.createSubDirectory(this.getClass().getSimpleName());
-
-        // If we have a test currently, let's remove the older files if they exist
-        if (getName() != null) {
-            BitmapDumper.deleteFileInClassFolder(this.getClass().getSimpleName(), getName());
-        }
-    }
+    private BitmapAsserter mBitmapAsserter = new BitmapAsserter(this.getClass().getSimpleName(),
+            name.getMethodName());
 
     protected DrawActivity getActivity() {
         return mActivityRule.getActivity();
@@ -99,10 +75,7 @@
 
     @Before
     public void setUp() {
-        mDifferenceVisualizer = new PassFailVisualizer();
-        if (USE_RS) {
-            mRenderScript = RenderScript.create(getActivity().getApplicationContext());
-        }
+        mBitmapAsserter.setUp(getActivity());
     }
 
     @After
@@ -153,54 +126,6 @@
         return takeScreenshot(testOffset);
     }
 
-    /**
-     * Compares the two bitmaps saved using the given test. If they fail, the files are saved using
-     * the test name.
-     */
-    protected void assertBitmapsAreSimilar(Bitmap bitmap1, Bitmap bitmap2,
-            BitmapComparer comparer, String debugMessage) {
-        boolean success;
-
-        if (USE_RS && comparer.supportsRenderScript()) {
-            Allocation idealAllocation = Allocation.createFromBitmap(mRenderScript, bitmap1,
-                    Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
-            Allocation givenAllocation = Allocation.createFromBitmap(mRenderScript, bitmap2,
-                    Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
-            success = comparer.verifySameRS(getActivity().getResources(), idealAllocation,
-                    givenAllocation, 0, TEST_WIDTH, TEST_WIDTH, TEST_HEIGHT, mRenderScript);
-        } else {
-            bitmap1.getPixels(mSoftwareArray, 0, TEST_WIDTH, 0, 0, TEST_WIDTH, TEST_HEIGHT);
-            bitmap2.getPixels(mHardwareArray, 0, TEST_WIDTH, 0, 0, TEST_WIDTH, TEST_HEIGHT);
-            success = comparer.verifySame(mSoftwareArray, mHardwareArray, 0, TEST_WIDTH, TEST_WIDTH,
-                    TEST_HEIGHT);
-        }
-
-        if (!success) {
-            BitmapDumper.dumpBitmaps(bitmap1, bitmap2, getName(), this.getClass().getSimpleName(),
-                    mDifferenceVisualizer);
-        }
-
-        assertTrue(debugMessage, success);
-    }
-
-    /**
-     * Tests to see if a bitmap passes a verifier's test. If it doesn't the bitmap is saved to the
-     * sdcard.
-     */
-    protected void assertBitmapIsVerified(Bitmap bitmap, BitmapVerifier bitmapVerifier,
-            String debugMessage) {
-        bitmap.getPixels(mSoftwareArray, 0, TEST_WIDTH, 0, 0,
-                TEST_WIDTH, TEST_HEIGHT);
-        boolean success = bitmapVerifier.verify(mSoftwareArray, 0, TEST_WIDTH, TEST_WIDTH, TEST_HEIGHT);
-        if (!success) {
-            Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, 0, 0, TEST_WIDTH, TEST_HEIGHT);
-            BitmapDumper.dumpBitmap(croppedBitmap, getName(), this.getClass().getSimpleName());
-            BitmapDumper.dumpBitmap(bitmapVerifier.getDifferenceBitmap(), getName() + "_verifier",
-                    this.getClass().getSimpleName());
-        }
-        assertTrue(debugMessage, success);
-    }
-
     protected TestCaseBuilder createTest() {
         mTestCaseBuilder = new TestCaseBuilder();
         return mTestCaseBuilder;
@@ -229,8 +154,8 @@
 
             for (TestCase testCase : mTestCases) {
                 Bitmap testCaseBitmap = captureRenderSpec(testCase);
-                assertBitmapsAreSimilar(idealBitmap, testCaseBitmap, bitmapComparer,
-                        testCase.getDebugString());
+                mBitmapAsserter.assertBitmapsAreSimilar(idealBitmap, testCaseBitmap, bitmapComparer,
+                        getName(), testCase.getDebugString());
             }
         }
 
@@ -245,7 +170,8 @@
 
             for (TestCase testCase : mTestCases) {
                 Bitmap testCaseBitmap = captureRenderSpec(testCase);
-                assertBitmapIsVerified(testCaseBitmap, bitmapVerifier, testCase.getDebugString());
+                mBitmapAsserter.assertBitmapIsVerified(testCaseBitmap, bitmapVerifier,
+                        getName(), testCase.getDebugString());
             }
         }
 
@@ -274,8 +200,8 @@
                         e.printStackTrace();
                     }
                     Bitmap testCaseBitmap = takeScreenshot(testOffset);
-                    assertBitmapIsVerified(testCaseBitmap, bitmapVerifier,
-                            testCase.getDebugString());
+                    mBitmapAsserter.assertBitmapIsVerified(testCaseBitmap, bitmapVerifier,
+                            getName(), testCase.getDebugString());
                 }
             }
         }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/MaterialActivity.java
similarity index 85%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
copy to tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/MaterialActivity.java
index 27a6fe2..53df12c 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/MaterialActivity.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.uirendering.cts.testinfrastructure;
 
 import android.app.Activity;
 
-public class BottomLeftLayoutActivity extends Activity {
+public class MaterialActivity extends Activity {
+
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
new file mode 100644
index 0000000..51e7dde
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
@@ -0,0 +1,115 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.renderscript.Allocation;
+import android.renderscript.RenderScript;
+import android.uirendering.cts.bitmapcomparers.BitmapComparer;
+import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
+import android.uirendering.cts.differencevisualizers.DifferenceVisualizer;
+import android.uirendering.cts.differencevisualizers.PassFailVisualizer;
+
+public class BitmapAsserter {
+    public static final boolean USE_RS = false;
+    private DifferenceVisualizer mDifferenceVisualizer;
+    private RenderScript mRenderScript;
+    private Context mContext;
+    private String mClassName;
+
+    public BitmapAsserter(String className, String name) {
+        mClassName = className;
+        mDifferenceVisualizer = new PassFailVisualizer();
+
+        // Create a location for the files to be held, if it doesn't exist already
+        BitmapDumper.createSubDirectory(mClassName);
+
+        // If we have a test currently, let's remove the older files if they exist
+        if (name != null) {
+            BitmapDumper.deleteFileInClassFolder(mClassName, name);
+        }
+    }
+
+    public void setUp(Context context) {
+        mDifferenceVisualizer = new PassFailVisualizer();
+        mContext = context;
+        if (USE_RS) {
+            mRenderScript = RenderScript.create(context.getApplicationContext());
+        }
+    }
+
+    /**
+     * Compares the two bitmaps saved using the given test. If they fail, the files are saved using
+     * the test name.
+     */
+    public void assertBitmapsAreSimilar(Bitmap bitmap1, Bitmap bitmap2, BitmapComparer comparer,
+            String testName, String debugMessage) {
+        boolean success;
+        int width = bitmap1.getWidth();
+        int height = bitmap1.getHeight();
+
+        if (width != bitmap2.getWidth() || height != bitmap2.getHeight()) {
+            fail("Can't compare bitmaps of different sizes");
+        }
+
+        if (USE_RS && comparer.supportsRenderScript()) {
+            Allocation idealAllocation = Allocation.createFromBitmap(mRenderScript, bitmap1,
+                    Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
+            Allocation givenAllocation = Allocation.createFromBitmap(mRenderScript, bitmap2,
+                    Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
+            success = comparer.verifySameRS(mContext.getResources(), idealAllocation,
+                    givenAllocation, 0, width, width, height, mRenderScript);
+        } else {
+            int[] pixels1 = new int[width * height];
+            int[] pixels2 = new int[width * height];
+            bitmap1.getPixels(pixels1, 0, width, 0, 0, width, height);
+            bitmap2.getPixels(pixels2, 0, width, 0, 0, width, height);
+            success = comparer.verifySame(pixels1, pixels2, 0, width, width, height);
+        }
+
+        if (!success) {
+            BitmapDumper.dumpBitmaps(bitmap1, bitmap2, testName, mClassName, mDifferenceVisualizer);
+        }
+
+        assertTrue(debugMessage, success);
+    }
+
+    /**
+     * Tests to see if a bitmap passes a verifier's test. If it doesn't the bitmap is saved to the
+     * sdcard.
+     */
+    public void assertBitmapIsVerified(Bitmap bitmap, BitmapVerifier bitmapVerifier,
+            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);
+        if (!success) {
+            Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
+            BitmapDumper.dumpBitmap(croppedBitmap, testName, mClassName);
+            BitmapDumper.dumpBitmap(bitmapVerifier.getDifferenceBitmap(), testName + "_verifier",
+                    this.getClass().getSimpleName());
+        }
+        assertTrue(debugMessage, success);
+    }
+
+
+}
diff --git a/tests/tests/util/Android.mk b/tests/tests/util/Android.mk
index cb1c70a..866e566 100644
--- a/tests/tests/util/Android.mk
+++ b/tests/tests/util/Android.mk
@@ -24,7 +24,7 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-annotations android-support-test ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/util/src/android/util/cts/LongSparseArrayTest.java b/tests/tests/util/src/android/util/cts/LongSparseArrayTest.java
index e5b23f8..cb4a153 100644
--- a/tests/tests/util/src/android/util/cts/LongSparseArrayTest.java
+++ b/tests/tests/util/src/android/util/cts/LongSparseArrayTest.java
@@ -179,4 +179,19 @@
         assertEquals(Long.MIN_VALUE, sparseArray.valueAt(3).longValue());
     }
 
+    public void testIndexOfValueByValue() {
+        LongSparseArray<String> sparseArray = new LongSparseArray<String>();
+        // Insert a number of String Objects into array
+        sparseArray.put(1L, "Index 0");
+        sparseArray.put(15L, "Index 1");
+        sparseArray.put(25L, "Index 2");
+        sparseArray.put(50L, "Index 3");
+        sparseArray.put(51L, "Index 4");
+
+        assertTrue(sparseArray.indexOfValueByValue("Index 0") == 0);
+        assertTrue(sparseArray.indexOfValueByValue("Index 1") == 1);
+        assertTrue(sparseArray.indexOfValueByValue("Index 2") == 2);
+        assertTrue(sparseArray.indexOfValueByValue("Index 3") == 3);
+        assertTrue(sparseArray.indexOfValueByValue("Index 4") == 4);
+    }
 }
diff --git a/tests/tests/util/src/android/util/cts/MutableTest.java b/tests/tests/util/src/android/util/cts/MutableTest.java
new file mode 100644
index 0000000..e4f6fd9
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/MutableTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.util.cts;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MutableTest {
+    @Test
+    public void testMutableBoolean() {
+        MutableBoolean mut = new MutableBoolean(false);
+        assertFalse(mut.value);
+        mut = new MutableBoolean(true);
+        assertTrue(mut.value);
+    }
+
+    @Test
+    public void testMutableByte() {
+        MutableByte mut = new MutableByte((byte) 127);
+        assertEquals(127, mut.value);
+        mut = new MutableByte((byte) -128);
+        assertEquals(-128, mut.value);
+    }
+
+    @Test
+    public void testMutableChar() {
+        MutableChar mut = new MutableChar('a');
+        assertEquals('a', mut.value);
+        mut = new MutableChar('b');
+        assertEquals('b', mut.value);
+    }
+
+    @Test
+    public void testMutableDouble() {
+        MutableDouble mut = new MutableDouble(0);
+        assertEquals(0, mut.value, 0);
+        mut = new MutableDouble(Double.MAX_VALUE);
+        assertEquals(Double.MAX_VALUE, mut.value, 0);
+    }
+
+    @Test
+    public void testMutableFloat() {
+        MutableFloat mut = new MutableFloat(0f);
+        assertEquals(0f, mut.value, 0);
+        mut = new MutableFloat(Float.MAX_VALUE);
+        assertEquals(Float.MAX_VALUE, mut.value, 0);
+    }
+
+    @Test
+    public void testMutableShort() {
+        MutableShort mut = new MutableShort((short) 0);
+        assertEquals(0, mut.value);
+        mut = new MutableShort(Short.MAX_VALUE);
+        assertEquals(Short.MAX_VALUE, mut.value);
+    }
+}
diff --git a/tests/tests/util/src/android/util/cts/PropertyTest.java b/tests/tests/util/src/android/util/cts/PropertyTest.java
index 22ad2c4..3d76e36 100644
--- a/tests/tests/util/src/android/util/cts/PropertyTest.java
+++ b/tests/tests/util/src/android/util/cts/PropertyTest.java
@@ -17,51 +17,62 @@
 package android.util.cts;
 
 import android.graphics.Point;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.FloatProperty;
 import android.util.IntProperty;
 import android.util.Property;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class PropertyTest extends TestCase {
+import static org.junit.Assert.*;
 
-    float mFloatValue = -1;
-    int mIntValue = -2;
-    Point mPointValue = new Point(-3, -4);
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PropertyTest {
+    private float mFloatValue = -1;
+    private int mIntValue = -2;
+    private Point mPointValue = new Point(-3, -4);
 
+    @Test
     public void testProperty() throws Exception {
         float testFloatValue = 5;
         Point testPointValue = new Point(10, 20);
 
         assertFalse(getFloatProp() == testFloatValue);
         assertFalse(getPointProp().equals(testPointValue));
-        assertEquals(RAW_FLOAT_PROP.get(this), getFloatProp());
-        assertEquals(RAW_POINT_PROP.get(this), getPointProp());
+        assertEquals(getFloatProp(), RAW_FLOAT_PROP.get(this), 0f);
+        assertEquals(getPointProp(), RAW_POINT_PROP.get(this));
 
         RAW_FLOAT_PROP.set(this, testFloatValue);
-        assertEquals(RAW_FLOAT_PROP.get(this), mFloatValue);
+        assertEquals(mFloatValue, RAW_FLOAT_PROP.get(this), 0f);
 
         RAW_POINT_PROP.set(this, testPointValue);
-        assertEquals(RAW_POINT_PROP.get(this), testPointValue);
+        assertEquals(testPointValue, RAW_POINT_PROP.get(this));
     }
 
+    @Test
     public void testFloatProperty() throws Exception {
-        float testFloatValue = 5;
+        assertFalse(getFloatProp() == 5);
+        assertEquals(getFloatProp(), FLOAT_PROP.get(this), 0f);
 
-        assertFalse(getFloatProp() == testFloatValue);
-        assertEquals(FLOAT_PROP.get(this), getFloatProp());
+        FLOAT_PROP.set(this, 5f);
+        assertEquals(5f, FLOAT_PROP.get(this), 0f);
 
-        FLOAT_PROP.set(this, testFloatValue);
-        assertEquals(FLOAT_PROP.get(this), testFloatValue);
+        FLOAT_PROP.setValue(this, 10);
+        assertEquals(10f, FLOAT_PROP.get(this), 0f);
     }
 
+    @Test
     public void testIntProperty() throws Exception {
-        int testIntValue = 5;
+        assertFalse(getIntProp() == 5);
+        assertEquals(getIntProp(), INT_PROP.get(this).intValue());
 
-        assertFalse(getIntProp() == testIntValue);
-        assertEquals(INT_PROP.get(this).intValue(), getIntProp());
+        INT_PROP.set(this, 5);
+        assertEquals(5, INT_PROP.get(this).intValue());
 
-        INT_PROP.set(this, testIntValue);
-        assertEquals(INT_PROP.get(this).intValue(), testIntValue);
+        INT_PROP.setValue(this, 10);
+        assertEquals(10, INT_PROP.get(this).intValue());
     }
 
     // Utility methods to get/set instance values. Used by Property classes below.
@@ -91,9 +102,9 @@
     }
 
     // Properties. RAW subclass from the generic Property class, the others subclass from
-    // the primtive-friendly IntProperty and FloatProperty subclasses.
+    // the primitive-friendly IntProperty and FloatProperty subclasses.
 
-    public static final Property<PropertyTest, Point> RAW_POINT_PROP =
+    private static final Property<PropertyTest, Point> RAW_POINT_PROP =
             new Property<PropertyTest, Point>(Point.class, "rawPoint") {
                 @Override
                 public void set(PropertyTest object, Point value) {
@@ -106,7 +117,7 @@
                 }
             };
 
-    public static final Property<PropertyTest, Float> RAW_FLOAT_PROP =
+    private static final Property<PropertyTest, Float> RAW_FLOAT_PROP =
             new Property<PropertyTest, Float>(Float.class, "rawFloat") {
                 @Override
                 public void set(PropertyTest object, Float value) {
@@ -119,7 +130,7 @@
                 }
             };
 
-    public static final Property<PropertyTest, Float> FLOAT_PROP =
+    private static final FloatProperty<PropertyTest> FLOAT_PROP =
             new FloatProperty<PropertyTest>("float") {
 
                 @Override
@@ -133,7 +144,7 @@
                 }
             };
 
-    public static final Property<PropertyTest, Integer> INT_PROP =
+    private static final IntProperty<PropertyTest> INT_PROP =
             new IntProperty<PropertyTest>("int") {
 
                 @Override
diff --git a/tests/tests/util/src/android/util/cts/RationalTest.java b/tests/tests/util/src/android/util/cts/RationalTest.java
index ab5c063..dabb29d 100644
--- a/tests/tests/util/src/android/util/cts/RationalTest.java
+++ b/tests/tests/util/src/android/util/cts/RationalTest.java
@@ -369,6 +369,34 @@
         }
     }
 
+    @SmallTest
+    public void testParseRational() {
+        assertEquals(new Rational(1, 2), Rational.parseRational("3:+6"));
+        assertEquals(new Rational(1, 2), Rational.parseRational("-3:-6"));
+        assertEquals(Rational.NaN, Rational.parseRational("NaN"));
+        assertEquals(Rational.POSITIVE_INFINITY, Rational.parseRational("Infinity"));
+        assertEquals(Rational.NEGATIVE_INFINITY, Rational.parseRational("-Infinity"));
+        assertEquals(Rational.ZERO, Rational.parseRational("0/261"));
+        assertEquals(Rational.NaN, Rational.parseRational("0/-0"));
+        assertEquals(Rational.POSITIVE_INFINITY, Rational.parseRational("1000/+0"));
+        assertEquals(Rational.NEGATIVE_INFINITY, Rational.parseRational("-1000/-0"));
+
+        try {
+            fail("Parsing " + Rational.parseRational("1.5") + " should not have succeeded");
+        } catch (NumberFormatException exception) {
+            // OK
+        }
+
+        try {
+            fail("Parsing " + Rational.parseRational("239") + " should not have succeeded");
+        } catch (NumberFormatException exception) {
+            // OK
+        }
+
+        Rational r = new Rational(10, 15);
+        assertEquals(r, Rational.parseRational(r.toString()));
+    }
+
     private static void assertValueEquals(Rational object, float expected) {
         assertEquals("Checking floatValue() for " + object + ";",
                 expected, object.floatValue());
diff --git a/tests/tests/util/src/android/util/cts/SizeTest.java b/tests/tests/util/src/android/util/cts/SizeTest.java
new file mode 100644
index 0000000..b0cc89b
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/SizeTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.util.cts;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Size;
+import android.util.SizeF;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SizeTest {
+    @Test
+    public void testConstructors() {
+        Size size = new Size(100, 200);
+        assertEquals(100, size.getWidth());
+        assertEquals(200, size.getHeight());
+
+        SizeF sizeF = new SizeF(100, 200);
+        assertEquals(100, sizeF.getWidth(), 0f);
+        assertEquals(200, sizeF.getHeight(), 0f);
+    }
+
+    @Test
+    public void testParseSize() {
+        try {
+            Size.parseSize("2by4");
+            fail("Should not be able to parse");
+        } catch (NumberFormatException ignored) {
+        }
+
+        assertEquals(new Size(100, 200), Size.parseSize("100*200"));
+        assertEquals(new Size(10, 20), Size.parseSize("10x20"));
+        assertEquals(new SizeF(9999, 9999), SizeF.parseSizeF("9999x9999"));
+    }
+
+    @Test
+    public void testParseSizeF() {
+        try {
+            SizeF.parseSizeF("2by4");
+            fail("Should not be able to parse");
+        } catch (NumberFormatException ignored) {
+        }
+
+        assertEquals(new SizeF(100f, 200f), SizeF.parseSizeF("100*200"));
+        assertEquals(new SizeF(10f, 20f), SizeF.parseSizeF("10x20"));
+        assertEquals(new SizeF(1000000f, 2.4f), SizeF.parseSizeF("1e6x2.4"));
+    }
+}
diff --git a/tests/tests/util/src/android/util/cts/SparseArrayTest.java b/tests/tests/util/src/android/util/cts/SparseArrayTest.java
index 6dbb571..3f4aadf 100644
--- a/tests/tests/util/src/android/util/cts/SparseArrayTest.java
+++ b/tests/tests/util/src/android/util/cts/SparseArrayTest.java
@@ -174,4 +174,20 @@
         assertEquals(20L, sparseArray.valueAt(2).longValue());
         assertEquals(Long.MIN_VALUE, sparseArray.valueAt(3).longValue());
     }
+
+    public void testIndexOfValueByValue() {
+        SparseArray<String> sparseArray = new SparseArray<String>();
+        // Insert a number of String Objects into array
+        sparseArray.put(1, "Index 0");
+        sparseArray.put(15, "Index 1");
+        sparseArray.put(25, "Index 2");
+        sparseArray.put(50, "Index 3");
+        sparseArray.put(51, "Index 4");
+
+        assertTrue(sparseArray.indexOfValueByValue("Index 0") == 0);
+        assertTrue(sparseArray.indexOfValueByValue("Index 1") == 1);
+        assertTrue(sparseArray.indexOfValueByValue("Index 2") == 2);
+        assertTrue(sparseArray.indexOfValueByValue("Index 3") == 3);
+        assertTrue(sparseArray.indexOfValueByValue("Index 4") == 4);
+    }
 }
diff --git a/tests/tests/util/src/android/util/cts/TypedValueTest.java b/tests/tests/util/src/android/util/cts/TypedValueTest.java
index 2ab91d9..735074f 100644
--- a/tests/tests/util/src/android/util/cts/TypedValueTest.java
+++ b/tests/tests/util/src/android/util/cts/TypedValueTest.java
@@ -205,4 +205,24 @@
 
         assertEquals(TypedValue.complexToDimension(10, dm), tv.getDimension(dm));
     }
+
+    public void testGetComplexUnit() {
+        TypedValue tv = new TypedValue();
+        tv.data = 256;
+        assertEquals(TypedValue.COMPLEX_UNIT_PX, tv.getComplexUnit());
+        tv.data = 257;
+        assertEquals(TypedValue.COMPLEX_UNIT_DIP, tv.getComplexUnit());
+        tv.data = 258;
+        assertEquals(TypedValue.COMPLEX_UNIT_SP, tv.getComplexUnit());
+        tv.data = 259;
+        assertEquals(TypedValue.COMPLEX_UNIT_PT, tv.getComplexUnit());
+        tv.data = 260;
+        assertEquals(TypedValue.COMPLEX_UNIT_IN, tv.getComplexUnit());
+        tv.data = 261;
+        assertEquals(TypedValue.COMPLEX_UNIT_MM, tv.getComplexUnit());
+        tv.data = 21474864;
+        assertEquals(TypedValue.COMPLEX_UNIT_FRACTION, tv.getComplexUnit());
+        tv.data = 21474865;
+        assertEquals(TypedValue.COMPLEX_UNIT_FRACTION_PARENT, tv.getComplexUnit());
+    }
 }
diff --git a/tests/tests/view/Android.mk b/tests/tests/view/Android.mk
index ba4be93..d6100c8 100644
--- a/tests/tests/view/Android.mk
+++ b/tests/tests/view/Android.mk
@@ -29,11 +29,12 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
     ctsdeviceutil \
     ctstestrunner \
     mockito-target \
-    ub-uiautomator \
-    android-support-test
+    platform-test-annotations \
+    ub-uiautomator
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsview_jni libnativehelper_compat_libc++
 
diff --git a/tests/tests/view/jni/Android.mk b/tests/tests/view/jni/Android.mk
index ac7b844..288e250 100644
--- a/tests/tests/view/jni/Android.mk
+++ b/tests/tests/view/jni/Android.mk
@@ -18,6 +18,8 @@
 
 LOCAL_MODULE := libctsview_jni
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := \
diff --git a/tests/tests/view/jni/CtsViewJniOnLoad.cpp b/tests/tests/view/jni/CtsViewJniOnLoad.cpp
index 2c1e643..1a7ef3c 100644
--- a/tests/tests/view/jni/CtsViewJniOnLoad.cpp
+++ b/tests/tests/view/jni/CtsViewJniOnLoad.cpp
@@ -16,8 +16,8 @@
  */
 #include <jni.h>
 
-#include <utils/Log.h>
 #define LOG_TAG "CtsViewJniOnLoad"
+#include <utils/Log.h>
 
 extern int register_android_view_cts_ChoreographerNativeTest(JNIEnv* env);
 
diff --git a/tests/tests/view/res/layout/textview_layout.xml b/tests/tests/view/res/layout/textview_layout.xml
index c09b93a..8b8418b 100644
--- a/tests/tests/view/res/layout/textview_layout.xml
+++ b/tests/tests/view/res/layout/textview_layout.xml
@@ -60,7 +60,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"/>
 
-            <android.view.cts.MockTextView
+            <TextView
                     android:id="@+id/mock_textview_left"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
@@ -70,7 +70,7 @@
                     android:gravity="left"
                     />
 
-            <android.view.cts.MockTextView
+            <TextView
                     android:id="@+id/mock_textview_right"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
@@ -80,7 +80,7 @@
                     android:gravity="right"
                     />
 
-            <android.view.cts.MockTextView
+            <TextView
                     android:id="@+id/mock_textview_center"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
diff --git a/tests/tests/view/src/android/view/cts/AbsSavedStateTest.java b/tests/tests/view/src/android/view/cts/AbsSavedStateTest.java
index 3662e2c..e4165bb 100644
--- a/tests/tests/view/src/android/view/cts/AbsSavedStateTest.java
+++ b/tests/tests/view/src/android/view/cts/AbsSavedStateTest.java
@@ -18,83 +18,128 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.support.test.filters.SmallTest;
 import android.test.InstrumentationTestCase;
 import android.view.AbsSavedState;
 
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+@SmallTest
 public class AbsSavedStateTest extends InstrumentationTestCase {
 
-    // constant for test of writeToParcel
-    public static final int TEST_NUMBER = 1;
-
     public void testConstructor() {
-        MockParcelable superState = new MockParcelable();
-        assertNotNull(superState);
-        new MockAbsSavedState(superState);
+        try {
+            new AbsSavedStateImpl((Parcelable) null);
+            fail("Expected NullPointerException");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            new AbsSavedStateImpl((Parcel) null);
+            fail("Expected NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected.
+        }
+
+        try {
+            new AbsSavedStateImpl(null, null);
+            fail("Expected NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected.
+        }
+
+        AbsSavedState superState = new AbsSavedStateImpl(Parcel.obtain());
+        assertNull(superState.getSuperState());
+
+        AbsSavedState s = new AbsSavedStateImpl(superState);
+        assertSame(superState, s.getSuperState());
 
         Parcel source = Parcel.obtain();
-        new MockAbsSavedState(source);
+        source.writeParcelable(superState, 0);
+        source.setDataPosition(0);
+        s = new AbsSavedStateImpl(source);
+        assertTrue(s.getSuperState() instanceof AbsSavedState);
 
-        MockAbsSavedState savedState = new MockAbsSavedState(source);
-        assertEquals(0, savedState.describeContents());
+        source = Parcel.obtain();
+        s = new AbsSavedStateImpl(source);
+        assertSame(AbsSavedState.EMPTY_STATE, s.getSuperState());
+
+        ClassLoader loader = AbsSavedState.class.getClassLoader();
+        source = Parcel.obtain();
+        source.writeParcelable(superState, 0);
+        source.setDataPosition(0);
+        s = new AbsSavedStateImpl(source, loader);
+        assertTrue(s.getSuperState() instanceof AbsSavedState);
+
+        source = Parcel.obtain();
+        s = new AbsSavedStateImpl(source, loader);
+        assertSame(AbsSavedState.EMPTY_STATE, s.getSuperState());
     }
 
-    public void testGetSuperState() {
-        MockParcelable superState = new MockParcelable();
-        assertNotNull(superState);
-        MockAbsSavedState savedState = new MockAbsSavedState(superState);
+    public void testCreator() {
+        int size = 10;
+        AbsSavedState[] array = AbsSavedState.CREATOR.newArray(size);
+        assertNotNull(array);
+        assertEquals(size, array.length);
+        for (AbsSavedState state : array) {
+            assertNull(state);
+        }
 
-        assertSame(superState, savedState.getSuperState());
+        AbsSavedState state = new AbsSavedStateImpl(AbsSavedState.EMPTY_STATE);
+        Parcel parcel = Parcel.obtain();
+        state.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        AbsSavedState unparceled = AbsSavedState.CREATOR.createFromParcel(parcel);
+        assertNotNull(unparceled);
+        assertEquals(AbsSavedState.EMPTY_STATE, unparceled.getSuperState());
+
+        AbsSavedState stateWithSuper = new AbsSavedStateImpl(state);
+        parcel = Parcel.obtain();
+        stateWithSuper.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        try {
+            AbsSavedState.CREATOR.createFromParcel(parcel);
+            fail("Expected IllegalStateException");
+        } catch (IllegalStateException e) {
+            // Expected.
+        }
     }
 
     public void testWriteToParcel() {
-        MockParcelable superState = new MockParcelable();
-        assertNotNull(superState);
-        MockAbsSavedState savedState = new MockAbsSavedState(superState);
-
+        Parcelable superState = mock(Parcelable.class);
+        AbsSavedState savedState = new AbsSavedStateImpl(superState);
         Parcel dest = Parcel.obtain();
         int flags = 2;
         savedState.writeToParcel(dest, flags);
-
-        // we instantiate the writeToParcel of Parcalable
-        // and give a return for test
-        assertEquals(TEST_NUMBER, superState.writeToParcelRunSymbol());
-        assertEquals(flags, superState.getFlags());
+        verify(superState).writeToParcel(eq(dest), eq(flags));
     }
 
-    static class MockAbsSavedState extends AbsSavedState {
-
-        public MockAbsSavedState(Parcelable superState) {
+    private static class AbsSavedStateImpl extends AbsSavedState {
+        AbsSavedStateImpl(Parcelable superState) {
             super(superState);
         }
 
-        public MockAbsSavedState(Parcel source) {
+        AbsSavedStateImpl(Parcel source) {
             super(source);
         }
-    }
 
-    static class MockParcelable implements Parcelable {
-
-        // Test for writeToParcel
-        private int mTest;
-        private int mFlags;
-
-        public int describeContents() {
-            return 0;
+        AbsSavedStateImpl(Parcel source, ClassLoader loader) {
+            super(source, loader);
         }
 
-        // Instantiate writeToParcel
-        public void writeToParcel(Parcel dest, int flags) {
-            mTest = TEST_NUMBER;
-            mFlags = flags;
-        }
+        public static final Creator<AbsSavedStateImpl> CREATOR = new Creator<AbsSavedStateImpl>() {
+            @Override
+            public AbsSavedStateImpl createFromParcel(Parcel source) {
+                return new AbsSavedStateImpl(source);
+            }
 
-        // For test of writeToParcel
-        public int writeToParcelRunSymbol() {
-            return mTest;
-        }
-
-        public int getFlags() {
-            return mFlags;
-        }
+            @Override
+            public AbsSavedStateImpl[] newArray(int size) {
+                return new AbsSavedStateImpl[size];
+            }
+        };
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/MockTextView.java b/tests/tests/view/src/android/view/cts/MockTextView.java
deleted file mode 100644
index 0c73614..0000000
--- a/tests/tests/view/src/android/view/cts/MockTextView.java
+++ /dev/null
@@ -1,224 +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.view.cts;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.text.method.MovementMethod;
-import android.util.AttributeSet;
-import android.view.ContextMenu;
-import android.view.KeyEvent;
-import android.widget.TextView;
-
-public class MockTextView extends TextView {
-    private boolean mHasCalledOnCreateContextMenu;
-    private boolean mHasCalledOnFocusChanged;
-    private boolean mHasCalledOnMeasure;
-    private boolean mHasCalledOnTextChanged;
-    private boolean mHasCalledDrawableStateChanged;
-    private boolean mHasCalledOnWindowFocusChanged;
-    private boolean mHasCalledOnPrivateIMECommand;
-    private boolean mHasCalledOnKeyMultiple;
-
-    public MockTextView(Context context) {
-        super(context);
-    }
-
-    public MockTextView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public MockTextView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    public boolean hasCalledOnWindowFocusChanged() {
-        return mHasCalledOnWindowFocusChanged;
-    }
-
-    public boolean hasCalledOnCreateContextMenu() {
-        return mHasCalledOnCreateContextMenu;
-    }
-
-    public boolean hasCalledDrawableStateChanged() {
-        return mHasCalledDrawableStateChanged;
-    }
-
-    public boolean hasCalledOnFocusChanged() {
-        return mHasCalledOnFocusChanged;
-    }
-
-    public boolean hasCalledOnMeasure() {
-        return mHasCalledOnMeasure;
-    }
-
-    public boolean hasCalledOnTextChanged() {
-        return mHasCalledOnTextChanged;
-    }
-
-    public boolean hasCalledOnPrivateIMECommand() {
-        return mHasCalledOnPrivateIMECommand;
-    }
-
-    public boolean hasCalledOnKeyMultiple(){
-        return mHasCalledOnKeyMultiple;
-    }
-
-    public void reset() {
-        mHasCalledOnWindowFocusChanged = false;
-        mHasCalledDrawableStateChanged = false;
-        mHasCalledOnCreateContextMenu = false;
-        mHasCalledOnFocusChanged = false;
-        mHasCalledOnMeasure = false;
-        mHasCalledOnTextChanged = false;
-        mHasCalledOnPrivateIMECommand = false;
-        mHasCalledOnKeyMultiple = false;
-    }
-
-    public int computeHorizontalScrollRange() {
-        return super.computeHorizontalScrollRange();
-    }
-
-    public int computeVerticalScrollRange() {
-        return super.computeVerticalScrollRange();
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        super.drawableStateChanged();
-        mHasCalledDrawableStateChanged = true;
-    }
-
-    public boolean getDefaultEditable() {
-        return super.getDefaultEditable();
-    }
-
-    public MovementMethod getDefaultMovementMethod() {
-        return super.getDefaultMovementMethod();
-    }
-
-    @Override
-    protected void onCreateContextMenu(ContextMenu menu) {
-        super.onCreateContextMenu(menu);
-        mHasCalledOnCreateContextMenu = true;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-    }
-
-    @Override
-    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
-        super.onFocusChanged(focused, direction, previouslyFocusedRect);
-        mHasCalledOnFocusChanged = true;
-    }
-
-    @Override
-    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
-        mHasCalledOnKeyMultiple = true;
-        return super.onKeyMultiple(keyCode, repeatCount, event);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        mHasCalledOnMeasure = true;
-    }
-
-    @Override
-    protected void onTextChanged(CharSequence text, int start, int before, int after) {
-        super.onTextChanged(text, start, before, after);
-        mHasCalledOnTextChanged = true;
-    }
-
-    public boolean setFrame(int l, int t, int r, int b) {
-        return super.setFrame(l, t, r, b);
-    }
-
-    @Override
-    public void onWindowFocusChanged(boolean hasWindowFocus) {
-        super.onWindowFocusChanged(hasWindowFocus);
-        mHasCalledOnWindowFocusChanged = true;
-    }
-
-    public float getLeftFadingEdgeStrength() {
-        return super.getLeftFadingEdgeStrength();
-    }
-
-    public float getRightFadingEdgeStrength() {
-        return super.getRightFadingEdgeStrength();
-    }
-
-    @Override
-    public boolean onPrivateIMECommand(String action, Bundle data) {
-        mHasCalledOnPrivateIMECommand = true;
-        return super.onPrivateIMECommand(action, data);
-    }
-
-    public int getFrameLeft() {
-        return getLeft();
-    }
-
-    public int getFrameTop() {
-        return getTop();
-    }
-
-    public int getFrameRight() {
-        return getRight();
-    }
-
-    public int getFrameBottom() {
-        return getBottom();
-    }
-
-    public int getBottomPaddingOffset() {
-        return super.getBottomPaddingOffset();
-    }
-
-    public int getLeftPaddingOffset() {
-        return super.getLeftPaddingOffset();
-    }
-
-    public int getRightPaddingOffset() {
-        return super.getRightPaddingOffset();
-    }
-
-    public int getTopPaddingOffset() {
-        return super.getTopPaddingOffset();
-    }
-
-    public boolean isPaddingOffsetRequired() {
-        return super.isPaddingOffsetRequired();
-    }
-
-    public boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who);
-    }
-
-    public int computeVerticalScrollExtent() {
-        return super.computeVerticalScrollExtent();
-    }
-}
diff --git a/tests/tests/view/src/android/view/cts/NumberPickerTest.java b/tests/tests/view/src/android/view/cts/NumberPickerTest.java
deleted file mode 100644
index 2e2733e..0000000
--- a/tests/tests/view/src/android/view/cts/NumberPickerTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc.
- *
- * 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.test.AndroidTestCase;
-import android.widget.NumberPicker;
-
-public class NumberPickerTest extends AndroidTestCase {
-
-    public void testSetDisplayedValues1() throws Exception {
-        NumberPicker numberPicker = new NumberPicker(getContext());
-        numberPicker.setMinValue(10);
-        numberPicker.setMaxValue(12);
-        numberPicker.setDisplayedValues(new String[]{"One", "Two", "Three"});
-    }
-
-    public void testSetDisplayedValues2() throws Exception {
-        NumberPicker numberPicker = new NumberPicker(getContext());
-        numberPicker.setMinValue(10);
-        numberPicker.setMaxValue(14);
-        try {
-            numberPicker.setDisplayedValues(new String[]{"One", "Two", "Three"});
-            fail("The size of the displayed values array must be equal to the selectable numbers!");
-        } catch (Exception e) {
-            /* expected */
-        }
-    }
-}
diff --git a/tests/tests/view/src/android/view/cts/TextureViewTest.java b/tests/tests/view/src/android/view/cts/TextureViewTest.java
index 12c689f..69eff68 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewTest.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewTest.java
@@ -17,6 +17,7 @@
 package android.view.cts;
 
 import android.app.Instrumentation;
+import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Point;
@@ -24,7 +25,6 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.view.View;
-import android.view.cts.util.ViewTestUtils;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -74,8 +74,8 @@
         updatedCount = mActivity.waitForSurfaceUpdateCount(1);
         assertEquals(1, updatedCount);
         assertEquals(Color.WHITE, getPixel(center));
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mActivity,
-                () -> mActivity.removeCover());
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation,
+                mActivity.findViewById(android.R.id.content), () -> mActivity.removeCover());
 
         int color;
         color = waitForChange(center, Color.WHITE);
diff --git a/tests/tests/view/src/android/view/cts/ViewOutlineProviderTest.java b/tests/tests/view/src/android/view/cts/ViewOutlineProviderTest.java
new file mode 100644
index 0000000..bf21b30
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/ViewOutlineProviderTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.annotation.NonNull;
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewOutlineProviderTest {
+    @Rule
+    public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MockActivity.class);
+
+    Activity getActivity() { return mActivityTestRule.getActivity(); }
+
+    @Test
+    public void testBackground() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            View view = new View(mActivityTestRule.getActivity());
+            view.setLeftTopRightBottom(100, 200, 300, 400);
+
+
+            Outline outline = new Outline();
+            outline.setAlpha(1.0f);
+            Rect queryRect = new Rect();
+
+
+            // No background - outline is 0 alpha, width x height rect
+            ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
+            outline.getRect(queryRect);
+            assertEquals(new Rect(0, 0, 200, 200), queryRect);
+            assertEquals(0f, outline.getAlpha(), 0f);
+
+
+            // With background - outline is passed directly from background
+            view.setBackground(new ColorDrawable(Color.BLACK) {
+                @Override
+                public void getOutline(@NonNull Outline outline) {
+                    outline.setRect(1, 2, 3, 4);
+                    outline.setAlpha(0.123f);
+                }
+            });
+            ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
+            outline.getRect(queryRect);
+            assertEquals(new Rect(1, 2, 3, 4), queryRect);
+            assertEquals(0.123f, outline.getAlpha(), 0f);
+        });
+    }
+
+
+    @Test
+    public void testBounds() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            View view = new View(mActivityTestRule.getActivity());
+
+            Outline outline = new Outline();
+            Rect queryRect = new Rect();
+            outline.setAlpha(0.123f);
+
+            view.setLeftTopRightBottom(1, 2, 3, 4);
+            ViewOutlineProvider.BOUNDS.getOutline(view, outline);
+            outline.getRect(queryRect);
+            assertEquals(new Rect(0, 0, 2, 2), queryRect); // local width/height
+            assertEquals(0.123f, outline.getAlpha(), 0f); // alpha not changed
+
+            view.setLeftTopRightBottom(100, 200, 300, 400);
+            ViewOutlineProvider.BOUNDS.getOutline(view, outline);
+            outline.getRect(queryRect);
+            assertEquals(new Rect(0, 0, 200, 200), queryRect); // local width/height
+            assertEquals(0.123f, outline.getAlpha(), 0f); // alpha not changed
+        });
+    }
+
+    @Test
+    public void testPaddedBounds() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            View view = new View(mActivityTestRule.getActivity());
+
+            Outline outline = new Outline();
+            Rect queryRect = new Rect();
+            outline.setAlpha(0.123f);
+
+            view.setLeftTopRightBottom(10, 20, 30, 40);
+            view.setPadding(0, 0, 0, 0);
+            ViewOutlineProvider.PADDED_BOUNDS.getOutline(view, outline);
+            outline.getRect(queryRect);
+            assertEquals(new Rect(0, 0, 20, 20), queryRect); // local width/height
+            assertEquals(0.123f, outline.getAlpha(), 0f); // alpha not changed
+
+            view.setPadding(5, 5, 5, 5);
+            ViewOutlineProvider.PADDED_BOUNDS.getOutline(view, outline);
+            outline.getRect(queryRect);
+            assertEquals(new Rect(5, 5, 15, 15), queryRect); // local width/height, inset by 5
+            assertEquals(0.123f, outline.getAlpha(), 0f); // alpha not changed
+        });
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 7d11c68..44e8755 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -21,10 +21,12 @@
 import android.graphics.BitmapFactory;
 import com.android.internal.view.menu.ContextMenuBuilder;
 
+import android.content.ClipData;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.cts.util.CtsTouchUtils;
 import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -42,7 +44,6 @@
 import android.os.SystemClock;
 import android.os.Vibrator;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
 import android.test.UiThreadTest;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
@@ -171,7 +172,7 @@
                         constructor.setAccessible(true);
                         constructor.newInstance(args);
                     } catch (Throwable t) {
-                        sCtorException = new Pair<Class<?>, Throwable>(clazz, t);
+                        sCtorException = new Pair<>(clazz, t);
                         break;
                     }
                 }
@@ -259,12 +260,7 @@
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
         // check whether it has started
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.startAnimation(animation);
-            }
-        });
+        runTestOnUiThread(() -> view.startAnimation(animation));
         getInstrumentation().waitForIdleSync();
 
         new PollingCheck() {
@@ -328,13 +324,8 @@
         final Button button = new Button(mActivity);
         final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
         final int btnHeight = view.getHeight()/3;
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addContentView(button,
-                        new LinearLayout.LayoutParams(WRAP_CONTENT, btnHeight));
-            }
-        });
+        runTestOnUiThread(() -> mActivity.addContentView(button,
+                new LinearLayout.LayoutParams(WRAP_CONTENT, btnHeight)));
         getInstrumentation().waitForIdleSync();
         button.getHitRect(rect);
         MockTouchDelegate delegate = new MockTouchDelegate(rect, button);
@@ -344,7 +335,7 @@
         view.setTouchDelegate(delegate);
         assertSame(delegate, view.getTouchDelegate());
         assertFalse(delegate.hasCalledOnTouchEvent());
-        TouchUtils.clickView(this, view);
+        CtsTouchUtils.emulateTapOnViewCenter(getInstrumentation(), view);
         assertTrue(view.hasCalledOnTouchEvent());
         assertTrue(delegate.hasCalledOnTouchEvent());
 
@@ -484,12 +475,7 @@
         final MockView mockView = new MockView(mActivity);
         assertEquals(-1, mockView.getOldWOnSizeChanged());
         assertEquals(-1, mockView.getOldHOnSizeChanged());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                viewGroup.addView(mockView);
-            }
-        });
+        runTestOnUiThread(() -> viewGroup.addView(mockView));
         getInstrumentation().waitForIdleSync();
         assertTrue(mockView.hasCalledOnSizeChanged());
         assertEquals(0, mockView.getOldWOnSizeChanged());
@@ -503,12 +489,7 @@
         int oldw = view.getWidth();
         int oldh = view.getHeight();
         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(200, 100);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams));
         getInstrumentation().waitForIdleSync();
         assertTrue(view.hasCalledOnSizeChanged());
         assertEquals(oldw, view.getOldWOnSizeChanged());
@@ -578,12 +559,7 @@
 
         view.reset();
         assertFalse(view.hasCalledOnLayout());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.requestLayout();
-            }
-        });
+        runTestOnUiThread(view::requestLayout);
         getInstrumentation().waitForIdleSync();
         assertTrue(view.hasCalledOnLayout());
     }
@@ -727,23 +703,13 @@
 
         // width is 0
         final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams1);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams1));
         getInstrumentation().waitForIdleSync();
         assertFalse(view.getGlobalVisibleRect(rect, point));
 
         // height is -10
         final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams2);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams2));
         getInstrumentation().waitForIdleSync();
         assertFalse(view.getGlobalVisibleRect(rect, point));
 
@@ -753,12 +719,7 @@
 
         final LinearLayout.LayoutParams layoutParams3 =
                 new LinearLayout.LayoutParams(halfWidth, halfHeight);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams3);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams3));
         getInstrumentation().waitForIdleSync();
         assertTrue(view.getGlobalVisibleRect(rect, point));
         assertEquals(rcParent.left, rect.left);
@@ -784,23 +745,13 @@
 
         // width is 0
         final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams1);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams1));
         getInstrumentation().waitForIdleSync();
         assertFalse(view.getGlobalVisibleRect(rect));
 
         // height is -10
         final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams2);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams2));
         getInstrumentation().waitForIdleSync();
         assertFalse(view.getGlobalVisibleRect(rect));
 
@@ -810,12 +761,7 @@
 
         final LinearLayout.LayoutParams layoutParams3 =
                 new LinearLayout.LayoutParams(halfWidth, halfHeight);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams3);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams3));
         getInstrumentation().waitForIdleSync();
         assertTrue(view.getGlobalVisibleRect(rect));
         assertEquals(rcParent.left, rect.left);
@@ -831,23 +777,13 @@
         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
         assertEquals(view.getWidth(), view.computeHorizontalScrollExtent());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollTo(12, 0);
-            }
-        });
+        runTestOnUiThread(() -> view.scrollTo(12, 0));
         getInstrumentation().waitForIdleSync();
         assertEquals(12, view.computeHorizontalScrollOffset());
         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
         assertEquals(view.getWidth(), view.computeHorizontalScrollExtent());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollBy(12, 0);
-            }
-        });
+        runTestOnUiThread(() -> view.scrollBy(12, 0));
         getInstrumentation().waitForIdleSync();
         assertEquals(24, view.computeHorizontalScrollOffset());
         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
@@ -855,12 +791,7 @@
 
         int newWidth = 200;
         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(newWidth, 100);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams));
         getInstrumentation().waitForIdleSync();
         assertEquals(24, view.computeHorizontalScrollOffset());
         assertEquals(newWidth, view.getWidth());
@@ -876,24 +807,14 @@
         assertEquals(view.getHeight(), view.computeVerticalScrollExtent());
 
         final int scrollToY = 34;
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollTo(0, scrollToY);
-            }
-        });
+        runTestOnUiThread(() -> view.scrollTo(0, scrollToY));
         getInstrumentation().waitForIdleSync();
         assertEquals(scrollToY, view.computeVerticalScrollOffset());
         assertEquals(view.getHeight(), view.computeVerticalScrollRange());
         assertEquals(view.getHeight(), view.computeVerticalScrollExtent());
 
         final int scrollByY = 200;
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollBy(0, scrollByY);
-            }
-        });
+        runTestOnUiThread(() -> view.scrollBy(0, scrollByY));
         getInstrumentation().waitForIdleSync();
         assertEquals(scrollToY + scrollByY, view.computeVerticalScrollOffset());
         assertEquals(view.getHeight(), view.computeVerticalScrollRange());
@@ -901,12 +822,7 @@
 
         int newHeight = 333;
         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(200, newHeight);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams));
         getInstrumentation().waitForIdleSync();
         assertEquals(scrollToY + scrollByY, view.computeVerticalScrollOffset());
         assertEquals(newHeight, view.getHeight());
@@ -922,24 +838,14 @@
         assertEquals(0f, view.getTopFadingEdgeStrength());
         assertEquals(0f, view.getBottomFadingEdgeStrength());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollTo(10, 10);
-            }
-        });
+        runTestOnUiThread(() -> view.scrollTo(10, 10));
         getInstrumentation().waitForIdleSync();
         assertEquals(1f, view.getLeftFadingEdgeStrength());
         assertEquals(0f, view.getRightFadingEdgeStrength());
         assertEquals(1f, view.getTopFadingEdgeStrength());
         assertEquals(0f, view.getBottomFadingEdgeStrength());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollTo(-10, -10);
-            }
-        });
+        runTestOnUiThread(() -> view.scrollTo(-10, -10));
         getInstrumentation().waitForIdleSync();
         assertEquals(0f, view.getLeftFadingEdgeStrength());
         assertEquals(1f, view.getRightFadingEdgeStrength());
@@ -1143,7 +1049,7 @@
     }
 
     private void focusableInTouchModeTest(View view, boolean inTouchMode) {
-        ArrayList<View> views = new ArrayList<View>();
+        ArrayList<View> views = new ArrayList<>();
 
         view.setFocusableInTouchMode(false);
         view.setFocusable(true);
@@ -1715,12 +1621,7 @@
         assertEquals(200, view.getMeasuredHeight());
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.requestLayout();
-            }
-        });
+        runTestOnUiThread(view::requestLayout);
         getInstrumentation().waitForIdleSync();
         assertTrue(view.hasCalledOnMeasure());
         assertEquals(100, view.getMeasuredWidth());
@@ -1728,12 +1629,7 @@
 
         view.reset();
         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(200, 100);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams));
         getInstrumentation().waitForIdleSync();
         assertTrue(view.hasCalledOnMeasure());
         assertEquals(200, view.getMeasuredWidth());
@@ -1786,13 +1682,8 @@
     public void testScheduleDrawable() {
         View view = new View(mActivity);
         Drawable drawable = new StateListDrawable();
-        Runnable what = new Runnable() {
-            @Override
-            public void run() {
-                // do nothing
-            }
-        };
-
+        // Does nothing.
+        Runnable what = () -> {};
         // mAttachInfo is null
         view.scheduleDrawable(drawable, what, 1000);
 
@@ -1814,11 +1705,8 @@
     public void testUnscheduleDrawable() {
         View view = new View(mActivity);
         Drawable drawable = new StateListDrawable();
-        Runnable what = new Runnable() {
-            @Override
-            public void run() {
-                // do nothing
-            }
+        Runnable what = () -> {
+            // do nothing
         };
 
         // mAttachInfo is null
@@ -2153,12 +2041,9 @@
 
     public void testOnKeyShortcut() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setFocusable(true);
-                view.requestFocus();
-            }
+        runTestOnUiThread(() -> {
+            view.setFocusable(true);
+            view.requestFocus();
         });
         getInstrumentation().waitForIdleSync();
         assertTrue(view.isFocused());
@@ -2172,12 +2057,7 @@
 
     public void testOnKeyMultiple() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setFocusable(true);
-            }
-        });
+        runTestOnUiThread(() -> view.setFocusable(true));
 
         assertFalse(view.hasCalledOnKeyMultiple());
         view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_ENTER));
@@ -2202,13 +2082,10 @@
 
     public void testOnTrackballEvent() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setEnabled(true);
-                view.setFocusable(true);
-                view.requestFocus();
-            }
+        runTestOnUiThread(() -> {
+            view.setEnabled(true);
+            view.setFocusable(true);
+            view.requestFocus();
         });
         getInstrumentation().waitForIdleSync();
 
@@ -2254,12 +2131,9 @@
 
     public void testDispatchUnhandledMove() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setFocusable(true);
-                view.requestFocus();
-            }
+        runTestOnUiThread(() -> {
+            view.setFocusable(true);
+            view.requestFocus();
         });
         getInstrumentation().waitForIdleSync();
 
@@ -2273,44 +2147,24 @@
         final MockView mockView = new MockView(mActivity);
         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                viewGroup.addView(mockView);
-            }
-        });
+        runTestOnUiThread(() -> viewGroup.addView(mockView));
         getInstrumentation().waitForIdleSync();
         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
 
         mockView.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setVisible(false);
-            }
-        });
+        runTestOnUiThread(() -> getActivity().setVisible(false));
         getInstrumentation().waitForIdleSync();
         assertTrue(mockView.hasCalledDispatchWindowVisibilityChanged());
         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
 
         mockView.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setVisible(true);
-            }
-        });
+        runTestOnUiThread(() -> getActivity().setVisible(true));
         getInstrumentation().waitForIdleSync();
         assertTrue(mockView.hasCalledDispatchWindowVisibilityChanged());
         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
 
         mockView.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                viewGroup.removeView(mockView);
-            }
-        });
+        runTestOnUiThread(() -> viewGroup.removeView(mockView));
         getInstrumentation().waitForIdleSync();
         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
     }
@@ -2326,22 +2180,12 @@
         assertEquals(200, rect.bottom);
 
         final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams1);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams1));
         getInstrumentation().waitForIdleSync();
         assertFalse(view.getLocalVisibleRect(rect));
 
         final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams2);
-            }
-        });
+        runTestOnUiThread(() -> view.setLayoutParams(layoutParams2));
         getInstrumentation().waitForIdleSync();
         assertFalse(view.getLocalVisibleRect(rect));
 
@@ -2351,12 +2195,9 @@
 
         final LinearLayout.LayoutParams layoutParams3 =
                 new LinearLayout.LayoutParams(halfWidth, halfHeight);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams3);
-                view.scrollTo(20, -30);
-            }
+        runTestOnUiThread(() -> {
+            view.setLayoutParams(layoutParams3);
+            view.scrollTo(20, -30);
         });
         getInstrumentation().waitForIdleSync();
         assertTrue(view.getLocalVisibleRect(rect));
@@ -2454,12 +2295,9 @@
 
     public void testOnKeyDownOrUp() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setFocusable(true);
-                view.requestFocus();
-            }
+        runTestOnUiThread(() -> {
+            view.setFocusable(true);
+            view.requestFocus();
         });
         getInstrumentation().waitForIdleSync();
         assertTrue(view.isFocused());
@@ -2481,12 +2319,9 @@
         assertFalse(view.isPressed());
         assertTrue(view.hasCalledOnKeyDown());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setEnabled(true);
-                view.setClickable(true);
-            }
+        runTestOnUiThread(() -> {
+            view.setEnabled(true);
+            view.setClickable(true);
         });
         view.reset();
         OnClickListenerImpl listener = new OnClickListenerImpl();
@@ -2556,33 +2391,24 @@
         // Add the child view to the parent, test that parent has same width as child
         // Remove the child view from the parent, test that parent is 0xparentHeight
         final CountDownLatch countDownLatch1 = new CountDownLatch(1);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                viewGroup.removeAllViews();
-                viewGroup.addView(parent);
-                checkBounds(viewGroup, parent, countDownLatch1, 0, 0, 0, parentHeight);
-            }
+        runTestOnUiThread(() -> {
+            viewGroup.removeAllViews();
+            viewGroup.addView(parent);
+            checkBounds(viewGroup, parent, countDownLatch1, 0, 0, 0, parentHeight);
         });
         countDownLatch1.await(500, TimeUnit.MILLISECONDS);
 
         final CountDownLatch countDownLatch2 = new CountDownLatch(1);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                parent.addView(child);
-                checkBounds(viewGroup, parent, countDownLatch2, 0, 0, childWidth, parentHeight);
-            }
+        runTestOnUiThread(() -> {
+            parent.addView(child);
+            checkBounds(viewGroup, parent, countDownLatch2, 0, 0, childWidth, parentHeight);
         });
         countDownLatch2.await(500, TimeUnit.MILLISECONDS);
 
         final CountDownLatch countDownLatch3 = new CountDownLatch(1);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                parent.removeView(child);
-                checkBounds(viewGroup, parent, countDownLatch3, 0, 0, 0, parentHeight);
-            }
+        runTestOnUiThread(() -> {
+            parent.removeView(child);
+            checkBounds(viewGroup, parent, countDownLatch3, 0, 0, 0, parentHeight);
         });
         countDownLatch3.await(500, TimeUnit.MILLISECONDS);
     }
@@ -2694,12 +2520,7 @@
         assertTrue(view.hasCalledOnDraw());
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.invalidate();
-            }
-        });
+        runTestOnUiThread(view::invalidate);
         getInstrumentation().waitForIdleSync();
         new PollingCheck() {
             @Override
@@ -2709,12 +2530,9 @@
         }.run();
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.INVISIBLE);
-                view.invalidate();
-            }
+        runTestOnUiThread(() -> {
+            view.setVisibility(View.INVISIBLE);
+            view.invalidate();
         });
         getInstrumentation().waitForIdleSync();
         assertFalse(view.hasCalledOnDraw());
@@ -2733,12 +2551,7 @@
         view.reset();
         final Rect dirty = new Rect(view.getLeft() + 1, view.getTop() + 1,
                 view.getLeft() + view.getWidth() / 2, view.getTop() + view.getHeight() / 2);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.invalidate(dirty);
-            }
-        });
+        runTestOnUiThread(() -> view.invalidate(dirty));
         getInstrumentation().waitForIdleSync();
         new PollingCheck() {
             @Override
@@ -2748,12 +2561,9 @@
         }.run();
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.INVISIBLE);
-                view.invalidate(dirty);
-            }
+        runTestOnUiThread(() -> {
+            view.setVisibility(View.INVISIBLE);
+            view.invalidate(dirty);
         });
         getInstrumentation().waitForIdleSync();
         assertFalse(view.hasCalledOnDraw());
@@ -2766,12 +2576,7 @@
         view.reset();
         final Rect dirty = new Rect(view.getLeft() + 1, view.getTop() + 1,
                 view.getLeft() + view.getWidth() / 2, view.getTop() + view.getHeight() / 2);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom);
-            }
-        });
+        runTestOnUiThread(() -> view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom));
         getInstrumentation().waitForIdleSync();
         new PollingCheck() {
             @Override
@@ -2781,12 +2586,9 @@
         }.run();
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.INVISIBLE);
-                view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom);
-            }
+        runTestOnUiThread(() -> {
+            view.setVisibility(View.INVISIBLE);
+            view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom);
         });
         getInstrumentation().waitForIdleSync();
         assertFalse(view.hasCalledOnDraw());
@@ -2798,12 +2600,9 @@
         final Drawable d2 = mResources.getDrawable(R.drawable.pass);
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setBackgroundDrawable(d1);
-                view.invalidateDrawable(d1);
-            }
+        runTestOnUiThread(() -> {
+            view.setBackgroundDrawable(d1);
+            view.invalidateDrawable(d1);
         });
         getInstrumentation().waitForIdleSync();
         new PollingCheck() {
@@ -2814,12 +2613,7 @@
         }.run();
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.invalidateDrawable(d2);
-            }
-        });
+        runTestOnUiThread(() -> view.invalidateDrawable(d2));
         getInstrumentation().waitForIdleSync();
         assertFalse(view.hasCalledOnDraw());
 
@@ -2921,12 +2715,7 @@
 
     public void testDraw() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.requestLayout();
-            }
-        });
+        runTestOnUiThread(view::requestLayout);
         getInstrumentation().waitForIdleSync();
 
         assertTrue(view.hasCalledOnDraw());
@@ -3103,16 +2892,13 @@
         assertFalse(view.isClickable());
         assertFalse(view.isLongClickable());
 
-        TouchUtils.clickView(this, view);
+        CtsTouchUtils.emulateTapOnViewCenter(getInstrumentation(), view);
         assertTrue(view.hasCalledOnTouchEvent());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setEnabled(true);
-                view.setClickable(true);
-                view.setLongClickable(true);
-            }
+        runTestOnUiThread(() -> {
+            view.setEnabled(true);
+            view.setClickable(true);
+            view.setLongClickable(true);
         });
         getInstrumentation().waitForIdleSync();
         assertTrue(view.isEnabled());
@@ -3396,45 +3182,34 @@
         final InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(
                 Context.INPUT_METHOD_SERVICE);
         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(300, 500);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mockView.setBackgroundDrawable(d);
-                mockView.setHorizontalFadingEdgeEnabled(true);
-                mockView.setVerticalFadingEdgeEnabled(true);
-                mockView.setLayoutParams(layoutParams);
-                scrollView.setLayoutParams(layoutParams);
+        runTestOnUiThread(() -> {
+            mockView.setBackgroundDrawable(d);
+            mockView.setHorizontalFadingEdgeEnabled(true);
+            mockView.setVerticalFadingEdgeEnabled(true);
+            mockView.setLayoutParams(layoutParams);
+            scrollView.setLayoutParams(layoutParams);
 
-                mockView.setFocusable(true);
-                mockView.requestFocus();
-                mockView.setScrollContainer(true);
-                scrollView.setScrollContainer(false);
-                imm.showSoftInput(mockView, 0);
-            }
+            mockView.setFocusable(true);
+            mockView.requestFocus();
+            mockView.setScrollContainer(true);
+            scrollView.setScrollContainer(false);
+            imm.showSoftInput(mockView, 0);
         });
         getInstrumentation().waitForIdleSync();
 
         // FIXME: why the size of view doesn't change?
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                imm.hideSoftInputFromInputMethod(mockView.getWindowToken(), 0);
-            }
-        });
+        runTestOnUiThread(() -> imm.hideSoftInputFromInputMethod(mockView.getWindowToken(), 0));
         getInstrumentation().waitForIdleSync();
     }
 
     public void testTouchMode() throws Throwable {
         final MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view);
         final View fitWindowsView = mActivity.findViewById(R.id.fit_windows);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mockView.setFocusableInTouchMode(true);
-                fitWindowsView.setFocusable(true);
-                fitWindowsView.requestFocus();
-            }
+        runTestOnUiThread(() -> {
+            mockView.setFocusableInTouchMode(true);
+            fitWindowsView.setFocusable(true);
+            fitWindowsView.requestFocus();
         });
         getInstrumentation().waitForIdleSync();
         assertTrue(mockView.isFocusableInTouchMode());
@@ -3446,23 +3221,13 @@
         assertFalse(mockView.isInTouchMode());
         assertFalse(fitWindowsView.isInTouchMode());
 
-        TouchUtils.tapView(this, mockView);
+        CtsTouchUtils.emulateTapOnViewCenter(getInstrumentation(), mockView);
         assertFalse(fitWindowsView.isFocused());
         assertFalse(mockView.isFocused());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mockView.requestFocus();
-            }
-        });
+        runTestOnUiThread(mockView::requestFocus);
         getInstrumentation().waitForIdleSync();
         assertTrue(mockView.isFocused());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                fitWindowsView.requestFocus();
-            }
-        });
+        runTestOnUiThread(fitWindowsView::requestFocus);
         getInstrumentation().waitForIdleSync();
         assertFalse(fitWindowsView.isFocused());
         assertTrue(mockView.isInTouchMode());
@@ -3472,12 +3237,7 @@
         getInstrumentation().sendKeySync(keyEvent);
         assertTrue(mockView.isFocused());
         assertFalse(fitWindowsView.isFocused());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                fitWindowsView.requestFocus();
-            }
-        });
+        runTestOnUiThread(fitWindowsView::requestFocus);
         getInstrumentation().waitForIdleSync();
         assertFalse(mockView.isFocused());
         assertTrue(fitWindowsView.isFocused());
@@ -3630,12 +3390,7 @@
         assertFalse(view.hasCalledOnStartTemporaryDetach());
         assertFalse(view.hasCalledOnFinishTemporaryDetach());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.dispatchStartTemporaryDetach();
-            }
-        });
+        runTestOnUiThread(view::dispatchStartTemporaryDetach);
         getInstrumentation().waitForIdleSync();
 
         assertTrue(view.isTemporarilyDetached());
@@ -3644,12 +3399,7 @@
         assertTrue(view.hasCalledOnStartTemporaryDetach());
         assertFalse(view.hasCalledOnFinishTemporaryDetach());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.dispatchFinishTemporaryDetach();
-            }
-        });
+        runTestOnUiThread(view::dispatchFinishTemporaryDetach);
         getInstrumentation().waitForIdleSync();
 
         assertFalse(view.isTemporarilyDetached());
@@ -3662,12 +3412,9 @@
     public void testKeyPreIme() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setFocusable(true);
-                view.requestFocus();
-            }
+        runTestOnUiThread(() -> {
+            view.setFocusable(true);
+            view.requestFocus();
         });
         getInstrumentation().waitForIdleSync();
 
@@ -3704,22 +3451,14 @@
         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
         final MockEditText editText = new MockEditText(mActivity);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                viewGroup.addView(editText);
-                editText.requestFocus();
-            }
+        runTestOnUiThread(() -> {
+            viewGroup.addView(editText);
+            editText.requestFocus();
         });
         getInstrumentation().waitForIdleSync();
         assertTrue(editText.isFocused());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                imm.showSoftInput(editText, 0);
-            }
-        });
+        runTestOnUiThread(() -> imm.showSoftInput(editText, 0));
         getInstrumentation().waitForIdleSync();
 
         new PollingCheck(TIMEOUT_DELTA) {
@@ -3731,14 +3470,11 @@
 
         assertTrue(editText.hasCalledOnCheckIsTextEditor());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(imm.isActive(editText));
-                assertFalse(editText.hasCalledCheckInputConnectionProxy());
-                imm.isActive(view);
-                assertTrue(editText.hasCalledCheckInputConnectionProxy());
-            }
+        runTestOnUiThread(() -> {
+            assertTrue(imm.isActive(editText));
+            assertFalse(editText.hasCalledCheckInputConnectionProxy());
+            imm.isActive(view);
+            assertTrue(editText.hasCalledCheckInputConnectionProxy());
         });
     }
 
@@ -3871,14 +3607,11 @@
         assertTrue(mv.hasCalledOnVisibilityAggregated());
         assertTrue(mv.getLastAggregatedVisibility());
 
-        final Runnable reset = new Runnable() {
-            @Override
-            public void run() {
-                grandparent.setVisibility(View.VISIBLE);
-                parent.setVisibility(View.VISIBLE);
-                mv.setVisibility(View.VISIBLE);
-                mv.reset();
-            }
+        final Runnable reset = () -> {
+            grandparent.setVisibility(View.VISIBLE);
+            parent.setVisibility(View.VISIBLE);
+            mv.setVisibility(View.VISIBLE);
+            mv.reset();
         };
 
         runTestOnUiThread(reset);
@@ -3896,40 +3629,29 @@
         assertFalse(mv.getLastAggregatedVisibility());
 
         runTestOnUiThread(reset);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                grandparent.setVisibility(View.GONE);
-                parent.setVisibility(View.GONE);
-                mv.setVisibility(View.VISIBLE);
+        runTestOnUiThread(() -> {
+            grandparent.setVisibility(View.GONE);
+            parent.setVisibility(View.GONE);
+            mv.setVisibility(View.VISIBLE);
 
-                grandparent.setVisibility(View.VISIBLE);
-            }
+            grandparent.setVisibility(View.VISIBLE);
         });
 
         assertTrue(mv.hasCalledOnVisibilityAggregated());
         assertFalse(mv.getLastAggregatedVisibility());
 
         runTestOnUiThread(reset);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                grandparent.setVisibility(View.GONE);
-                parent.setVisibility(View.INVISIBLE);
+        runTestOnUiThread(() -> {
+            grandparent.setVisibility(View.GONE);
+            parent.setVisibility(View.INVISIBLE);
 
-                grandparent.setVisibility(View.VISIBLE);
-            }
+            grandparent.setVisibility(View.VISIBLE);
         });
 
         assertTrue(mv.hasCalledOnVisibilityAggregated());
         assertFalse(mv.getLastAggregatedVisibility());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                parent.setVisibility(View.VISIBLE);
-            }
-        });
+        runTestOnUiThread(() -> parent.setVisibility(View.VISIBLE));
 
         assertTrue(mv.getLastAggregatedVisibility());
     }
@@ -3967,13 +3689,42 @@
         assertTrue(overridingView.hasOverlappingRendering());
     }
 
+    public void testUpdateDragShadow() {
+        View view = mActivity.findViewById(R.id.fit_windows);
+        assertTrue(view.isAttachedToWindow());
+
+        View.DragShadowBuilder shadowBuilder = mock(View.DragShadowBuilder.class);
+        view.startDragAndDrop(ClipData.newPlainText("", ""), shadowBuilder, view, 0);
+        reset(shadowBuilder);
+
+        view.updateDragShadow(shadowBuilder);
+        // TODO: Verify with the canvas from the drag surface instead.
+        verify(shadowBuilder).onDrawShadow(any(Canvas.class));
+    }
+
+    public void testUpdateDragShadow_detachedView() {
+        View view = new View(mActivity);
+        assertFalse(view.isAttachedToWindow());
+
+        View.DragShadowBuilder shadowBuilder = mock(View.DragShadowBuilder.class);
+        view.startDragAndDrop(ClipData.newPlainText("", ""), shadowBuilder, view, 0);
+        reset(shadowBuilder);
+
+        view.updateDragShadow(shadowBuilder);
+        verify(shadowBuilder, never()).onDrawShadow(any(Canvas.class));
+    }
+
+    public void testUpdateDragShadow_noActiveDrag() {
+        View view = mActivity.findViewById(R.id.fit_windows);
+        assertTrue(view.isAttachedToWindow());
+
+        View.DragShadowBuilder shadowBuilder = mock(View.DragShadowBuilder.class);
+        view.updateDragShadow(shadowBuilder);
+        verify(shadowBuilder, never()).onDrawShadow(any(Canvas.class));
+    }
+
     private void setVisibilityOnUiThread(final View view, final int visibility) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(visibility);
-            }
-        });
+        runTestOnUiThread(() -> view.setVisibility(visibility));
     }
 
     private static class MockOverlappingRenderingSubclass extends View {
diff --git a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
index b799e76..32528fa 100644
--- a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
@@ -20,9 +20,9 @@
 
 import android.app.Activity;
 import android.app.Instrumentation;
+import android.cts.util.CtsTouchUtils;
 import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
@@ -60,12 +60,7 @@
     }
 
     private void layout(final int layoutId) {
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(layoutId);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mActivity.setContentView(layoutId));
         mInstrumentation.waitForIdleSync();
     }
 
@@ -74,24 +69,14 @@
         final View view1 = mActivity.findViewById(R.id.view1);
         final View view2 = mActivity.findViewById(R.id.view2);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view1.requestFocus();
-            }
-        });
+        mInstrumentation.runOnMainSync(view1::requestFocus);
 
         mViewTreeObserver = layout.getViewTreeObserver();
         final MockOnGlobalFocusChangeListener listener = new MockOnGlobalFocusChangeListener();
         mViewTreeObserver.addOnGlobalFocusChangeListener(listener);
         assertFalse(listener.hasCalledOnGlobalFocusChanged());
 
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view2.requestFocus();
-            }
-        });
+        mInstrumentation.runOnMainSync(view2::requestFocus);
         mInstrumentation.waitForIdleSync();
         new PollingCheck() {
             @Override
@@ -129,7 +114,7 @@
         final Button b = (Button) mActivity.findViewById(R.id.button1);
 
         // let the button be touch mode.
-        TouchUtils.tapView(this, b);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, b);
 
         mViewTreeObserver = b.getViewTreeObserver();
 
@@ -137,12 +122,7 @@
         assertFalse(listener.hasCalledOnTouchModeChanged());
         mViewTreeObserver.addOnTouchModeChangeListener(listener);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                b.requestFocusFromTouch();
-            }
-        });
+        mInstrumentation.runOnMainSync(b::requestFocusFromTouch);
         mInstrumentation.waitForIdleSync();
 
         new PollingCheck() {
@@ -204,23 +184,13 @@
         final View view1 = mActivity.findViewById(R.id.view1);
         final View view2 = mActivity.findViewById(R.id.view2);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view1.requestFocus();
-            }
-        });
+        mInstrumentation.runOnMainSync(view1::requestFocus);
 
         mViewTreeObserver = layout.getViewTreeObserver();
         final MockOnGlobalFocusChangeListener listener = new MockOnGlobalFocusChangeListener();
         mViewTreeObserver.addOnGlobalFocusChangeListener(listener);
         assertFalse(listener.hasCalledOnGlobalFocusChanged());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view2.requestFocus();
-            }
-        });
+        mInstrumentation.runOnMainSync(view2::requestFocus);
         mInstrumentation.waitForIdleSync();
         new PollingCheck() {
             @Override
@@ -233,12 +203,7 @@
         listener.reset();
         mViewTreeObserver.removeOnGlobalFocusChangeListener(listener);
         assertFalse(listener.hasCalledOnGlobalFocusChanged());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view1.requestFocus();
-            }
-        });
+        mInstrumentation.runOnMainSync(view1::requestFocus);
         mInstrumentation.waitForIdleSync();
         new PollingCheck() {
             @Override
@@ -268,19 +233,14 @@
     public void testRemoveOnTouchModeChangeListener() {
         final Button b = (Button) mActivity.findViewById(R.id.button1);
         // let the button be touch mode.
-        TouchUtils.tapView(this, b);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, b);
 
         mViewTreeObserver = b.getViewTreeObserver();
 
         MockOnTouchModeChangeListener listener = new MockOnTouchModeChangeListener();
         mViewTreeObserver.addOnTouchModeChangeListener(listener);
         assertFalse(listener.hasCalledOnTouchModeChanged());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                b.requestFocusFromTouch();
-            }
-        });
+        mInstrumentation.runOnMainSync(b::requestFocusFromTouch);
         mInstrumentation.waitForIdleSync();
         final MockOnTouchModeChangeListener l = listener;
         new PollingCheck() {
@@ -292,12 +252,7 @@
 
         listener = new MockOnTouchModeChangeListener();
         assertFalse(listener.hasCalledOnTouchModeChanged());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                b.requestFocusFromTouch();
-            }
-        });
+        mInstrumentation.runOnMainSync(b::requestFocusFromTouch);
         mInstrumentation.waitForIdleSync();
         final MockOnTouchModeChangeListener l2 = listener;
         new PollingCheck() {
@@ -318,12 +273,7 @@
         assertFalse(listener.hasCalledOnScrollChanged());
         mViewTreeObserver.addOnScrollChangedListener(listener);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scrollView.fullScroll(View.FOCUS_DOWN);
-            }
-        });
+        runTestOnUiThread(() -> scrollView.fullScroll(View.FOCUS_DOWN));
         mInstrumentation.waitForIdleSync();
         new PollingCheck() {
             @Override
@@ -336,12 +286,7 @@
         assertFalse(listener.hasCalledOnScrollChanged());
 
         mViewTreeObserver.removeOnScrollChangedListener(listener);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scrollView.fullScroll(View.FOCUS_UP);
-            }
-        });
+        runTestOnUiThread(() -> scrollView.fullScroll(View.FOCUS_UP));
         assertFalse(listener.hasCalledOnScrollChanged());
     }
 
diff --git a/tests/tests/view/src/android/view/cts/View_BaseSavedStateTest.java b/tests/tests/view/src/android/view/cts/View_BaseSavedStateTest.java
index ce64a18..8ce70f2 100644
--- a/tests/tests/view/src/android/view/cts/View_BaseSavedStateTest.java
+++ b/tests/tests/view/src/android/view/cts/View_BaseSavedStateTest.java
@@ -16,15 +16,86 @@
 
 package android.view.cts;
 
-
 import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.test.filters.SmallTest;
 import android.test.InstrumentationTestCase;
+import android.view.AbsSavedState;
 import android.view.View.BaseSavedState;
 
-public class View_BaseSavedStateTest extends InstrumentationTestCase {
-    public void testConstructors() {
-        BaseSavedState state = new BaseSavedState(Parcel.obtain());
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
-        new BaseSavedState(state);
+@SmallTest
+public class View_BaseSavedStateTest extends InstrumentationTestCase {
+
+    public void testConstructors() {
+        try {
+            new BaseSavedState((Parcelable) null);
+            fail("Expected NullPointerException");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
+        try {
+            new BaseSavedState((Parcel) null);
+            fail("Expected NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected.
+        }
+
+        try {
+            new BaseSavedState(null, null);
+            fail("Expected NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected.
+        }
+
+        BaseSavedState superState = new BaseSavedState(Parcel.obtain());
+        assertEquals(AbsSavedState.EMPTY_STATE, superState.getSuperState());
+
+        BaseSavedState s = new BaseSavedState(superState);
+        assertEquals(superState, s.getSuperState());
+
+        Parcel source = Parcel.obtain();
+        source.writeParcelable(superState, 0);
+        source.setDataPosition(0);
+        s = new BaseSavedState(source);
+        assertTrue(s.getSuperState() instanceof BaseSavedState);
+
+        ClassLoader loader = BaseSavedState.class.getClassLoader();
+        source = Parcel.obtain();
+        source.writeParcelable(superState, 0);
+        source.setDataPosition(0);
+        s = new BaseSavedState(source, loader);
+        assertTrue(s.getSuperState() instanceof BaseSavedState);
+    }
+
+    public void testCreator() {
+        int size = 10;
+        BaseSavedState[] array = BaseSavedState.CREATOR.newArray(size);
+        assertNotNull(array);
+        assertEquals(size, array.length);
+        for (BaseSavedState state : array) {
+            assertNull(state);
+        }
+
+        BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
+        Parcel parcel = Parcel.obtain();
+        state.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        BaseSavedState unparceled = BaseSavedState.CREATOR.createFromParcel(parcel);
+        assertNotNull(unparceled);
+        assertEquals(AbsSavedState.EMPTY_STATE, unparceled.getSuperState());
+    }
+
+    public void testWriteToParcel() {
+        Parcelable superState = mock(Parcelable.class);
+        BaseSavedState savedState = new BaseSavedState(superState);
+        Parcel dest = Parcel.obtain();
+        int flags = 2;
+        savedState.writeToParcel(dest, flags);
+        verify(superState).writeToParcel(eq(dest), eq(flags));
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java b/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java
index 413c356..697ed82 100644
--- a/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java
+++ b/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java
@@ -21,11 +21,11 @@
 
 import android.app.Activity;
 import android.app.Instrumentation;
+import android.cts.util.CtsTouchUtils;
 import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
 import android.test.UiThreadTest;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -357,7 +357,7 @@
         assertNull(onLongClickListener.getView());
 
         mInstrumentation.waitForIdleSync();
-        TouchUtils.longClickView(this, mEditText);
+        CtsTouchUtils.emulateLongClick(mInstrumentation, mEditText);
         new PollingCheck() {
             @Override
             protected boolean check() {
@@ -367,55 +367,35 @@
         assertSame(mEditText, onLongClickListener.getView());
 
         // click the Cancel button
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mEditText.setText("Germany");
-            }
-        });
+        runTestOnUiThread(() -> mEditText.setText("Germany"));
         mInstrumentation.waitForIdleSync();
 
-        TouchUtils.clickView(this, mButtonCancel);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mButtonCancel);
         assertEquals("", mEditText.getText().toString());
 
         // click the OK button
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mEditText.setText(ARGENTINA);
-            }
-        });
+        runTestOnUiThread(() -> mEditText.setText(ARGENTINA));
         mInstrumentation.waitForIdleSync();
 
-        TouchUtils.clickView(this, mButtonOk);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mButtonOk);
         assertEquals(ARGENTINA_SYMBOL, mSymbolTextView.getText().toString());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mEditText.setText(AMERICA);
-            }
-        });
+        runTestOnUiThread(() -> mEditText.setText(AMERICA));
         mInstrumentation.waitForIdleSync();
 
-        TouchUtils.clickView(this, mButtonOk);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mButtonOk);
         assertEquals(AMERICA_SYMBOL, mSymbolTextView.getText().toString());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mEditText.setText(CHINA);
-            }
-        });
+        runTestOnUiThread(() -> mEditText.setText(CHINA));
         mInstrumentation.waitForIdleSync();
 
-        TouchUtils.clickView(this, mButtonOk);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mButtonOk);
         assertEquals(CHINA_SYMBOL, mSymbolTextView.getText().toString());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mEditText.setText("Unknown");
-            }
-        });
+        runTestOnUiThread(() -> mEditText.setText("Unknown"));
         mInstrumentation.waitForIdleSync();
 
-        TouchUtils.clickView(this, mButtonOk);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mButtonOk);
         assertEquals(View.VISIBLE, mWarningTextView.getVisibility());
     }
 
diff --git a/tests/tests/view/src/android/view/cts/util/ViewTestUtils.java b/tests/tests/view/src/android/view/cts/util/ViewTestUtils.java
deleted file mode 100644
index b70e882..0000000
--- a/tests/tests/view/src/android/view/cts/util/ViewTestUtils.java
+++ /dev/null
@@ -1,69 +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.view.cts.util;
-
-import junit.framework.Assert;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnDrawListener;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Utilities for testing View behavior.
- */
-public class ViewTestUtils {
-
-    /**
-     * Runs the specified Runnable on the main thread and ensures that the
-     * specified View's tree is drawn before returning.
-     *
-     * @param instrumentation the instrumentation used to run the test
-     * @param view the view whose tree should be drawn before returning
-     * @param runner the runnable to run on the main thread
-     */
-    public static void runOnMainAndDrawSync(Instrumentation instrumentation,
-            final Activity activity, final Runnable runner) {
-        final CountDownLatch latch = new CountDownLatch(1);
-
-        instrumentation.runOnMainSync(() -> {
-            final View view = activity.findViewById(android.R.id.content);
-            final ViewTreeObserver observer = view.getViewTreeObserver();
-            final OnDrawListener listener = new OnDrawListener() {
-                @Override
-                public void onDraw() {
-                    observer.removeOnDrawListener(this);
-                    view.post(() -> latch.countDown());
-                }
-            };
-
-            observer.addOnDrawListener(listener);
-            runner.run();
-        });
-
-        try {
-            Assert.assertTrue("Expected draw pass occurred within 5 seconds",
-                    latch.await(5, TimeUnit.SECONDS));
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
index 4bc9eee..3d4cead 100644
--- a/tests/tests/widget/Android.mk
+++ b/tests/tests/widget/Android.mk
@@ -22,10 +22,12 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 LOCAL_STATIC_JAVA_LIBRARIES += \
+    android-support-test \
     mockito-target \
     android-common \
     ctsdeviceutil \
-    ctstestrunner
+    ctstestrunner \
+    platform-test-annotations
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index 224966d..0a60bf9 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -19,6 +19,7 @@
     package="android.widget.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
     <application android:label="Android TestCase"
             android:icon="@drawable/size_48x48"
             android:maxRecents="1"
@@ -92,9 +93,25 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.SpinnerCtsActivity"
+                  android:label="SpinnerCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.widget.cts.ToolbarCtsActivity"
-            android:theme="@android:style/Theme.Material.Light.NoActionBar"
-            android:label="ToolbarCtsActivity">
+                  android:theme="@android:style/Theme.Material.Light.NoActionBar"
+                  android:label="ToolbarCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.ActionMenuViewCtsActivity"
+                  android:label="ActionMenuViewCtsActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -149,6 +166,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.AbsSeekBarCtsActivity"
+            android:label="AbsSeekBarCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.widget.cts.ProgressBarCtsActivity"
             android:label="ProgressBarCtsActivity">
             <intent-filter>
@@ -189,8 +214,16 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="android.widget.cts.ExpandableListSimple"
-            android:label="ExpandableListSimple">
+        <activity android:name="android.widget.cts.ExpandableListBasic"
+                  android:label="ExpandableListBasic">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.ExpandableList"
+                  android:label="ExpandableList">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -246,7 +279,15 @@
         </activity>
 
         <activity android:name="android.widget.cts.ListViewCtsActivity"
-            android:label="ListViewCtsActivity">
+                  android:label="ListViewCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.ListViewFixedCtsActivity"
+                  android:label="ListViewFixedCtsActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -388,6 +429,70 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.DatePickerCtsActivity"
+                  android:label="DatePickerCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.SearchViewCtsActivity"
+                  android:label="SearchViewCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.ImageButtonCtsActivity"
+                  android:label="ImageButtonCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.NumberPickerCtsActivity"
+                  android:label="NumberPickerCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.CheckBoxCtsActivity"
+                  android:label="CheckBoxCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.RadioButtonCtsActivity"
+                  android:label="RadioButtonCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.ToggleButtonCtsActivity"
+                  android:label="ToggleButtonCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.TimePickerCtsActivity"
+                  android:label="TimePickerCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.app.ActivityGroup"
             android:label="ActivityGroup" />
 
@@ -405,6 +510,17 @@
             </intent-filter>
         </activity>
 
+        <receiver android:name="android.widget.cts.appwidget.MyAppWidgetProvider" >
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+            </intent-filter>
+            <meta-data android:name="android.appwidget.provider"
+                       android:resource="@xml/remoteviews_appwidget_info" />
+        </receiver>
+
+        <service android:name="android.widget.cts.appwidget.MyAppWidgetService"
+                 android:permission="android.permission.BIND_REMOTEVIEWS"
+                 android:exported="false" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/widget/res/drawable/blue_fill.xml b/tests/tests/widget/res/drawable/blue_fill.xml
index 5a24f08..383e7db 100644
--- a/tests/tests/widget/res/drawable/blue_fill.xml
+++ b/tests/tests/widget/res/drawable/blue_fill.xml
@@ -17,5 +17,5 @@
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="#0000FF" />
+    <solid android:color="#00F" />
 </shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/green_fill.xml b/tests/tests/widget/res/drawable/green_fill.xml
new file mode 100644
index 0000000..76c1101
--- /dev/null
+++ b/tests/tests/widget/res/drawable/green_fill.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#0F0" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/linear_layout_divider_magenta.xml b/tests/tests/widget/res/drawable/linear_layout_divider_magenta.xml
new file mode 100644
index 0000000..2dbd654
--- /dev/null
+++ b/tests/tests/widget/res/drawable/linear_layout_divider_magenta.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid
+        android:color="#F0F" />
+    <size
+        android:width="@dimen/linear_layout_divider_size"
+        android:height="@dimen/linear_layout_divider_size" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/linear_layout_divider_red.xml b/tests/tests/widget/res/drawable/linear_layout_divider_red.xml
new file mode 100644
index 0000000..56e88ef
--- /dev/null
+++ b/tests/tests/widget/res/drawable/linear_layout_divider_red.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid
+        android:color="#F00" />
+    <size
+        android:width="@dimen/linear_layout_divider_size"
+        android:height="@dimen/linear_layout_divider_size" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/magenta_fill.xml b/tests/tests/widget/res/drawable/magenta_fill.xml
index cbb594f..8b6da76 100644
--- a/tests/tests/widget/res/drawable/magenta_fill.xml
+++ b/tests/tests/widget/res/drawable/magenta_fill.xml
@@ -17,5 +17,5 @@
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="#FF00FF" />
+    <solid android:color="#F0F" />
 </shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/red_fill.xml b/tests/tests/widget/res/drawable/red_fill.xml
index e443240..8baf5b6 100644
--- a/tests/tests/widget/res/drawable/red_fill.xml
+++ b/tests/tests/widget/res/drawable/red_fill.xml
@@ -17,5 +17,5 @@
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="#8F00" />
+    <solid android:color="#F00" />
 </shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/red_translucent_fill.xml b/tests/tests/widget/res/drawable/red_translucent_fill.xml
new file mode 100644
index 0000000..edfbfa0
--- /dev/null
+++ b/tests/tests/widget/res/drawable/red_translucent_fill.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#80FF0000" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/yellow_fill.xml b/tests/tests/widget/res/drawable/yellow_fill.xml
index 3bd8097..44f88c4 100644
--- a/tests/tests/widget/res/drawable/yellow_fill.xml
+++ b/tests/tests/widget/res/drawable/yellow_fill.xml
@@ -17,5 +17,5 @@
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="#FFFF00" />
+    <solid android:color="#FF0" />
 </shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/actionmenuview_layout.xml b/tests/tests/widget/res/layout/actionmenuview_layout.xml
new file mode 100644
index 0000000..5d2895e
--- /dev/null
+++ b/tests/tests/widget/res/layout/actionmenuview_layout.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/button" />
+
+    <ActionMenuView
+        android:id="@+id/action_menu_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
+
diff --git a/tests/tests/widget/res/layout/autocompletetextview_layout.xml b/tests/tests/widget/res/layout/autocompletetextview_layout.xml
index 27eccab..8e023a1 100644
--- a/tests/tests/widget/res/layout/autocompletetextview_layout.xml
+++ b/tests/tests/widget/res/layout/autocompletetextview_layout.xml
@@ -24,10 +24,11 @@
         android:layout_height="wrap_content"
         android:text="@string/notify" />
 
-    <android.widget.cts.AutoCompleteTextViewNoIme android:id="@+id/autocompletetv_edit"
-        android:completionThreshold="1"
-        android:completionHint="@string/tabs_1"
+    <android.widget.cts.AutoCompleteTextViewNoIme
+        android:id="@+id/autocompletetv_edit"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:completionThreshold="1"
+        android:completionHint="@string/tabs_1"
         android:inputType="none"/>
 </LinearLayout>
diff --git a/tests/tests/widget/res/layout/calendarview_layout.xml b/tests/tests/widget/res/layout/calendarview_layout.xml
index 3bc5e47..507d48e 100644
--- a/tests/tests/widget/res/layout/calendarview_layout.xml
+++ b/tests/tests/widget/res/layout/calendarview_layout.xml
@@ -17,6 +17,7 @@
 
 <ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scroller"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:fillViewport="true">
diff --git a/tests/tests/widget/res/layout/checkbox_layout.xml b/tests/tests/widget/res/layout/checkbox_layout.xml
index a1f1718..c922436 100644
--- a/tests/tests/widget/res/layout/checkbox_layout.xml
+++ b/tests/tests/widget/res/layout/checkbox_layout.xml
@@ -14,12 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
 
-    <CheckBox android:id="@+id/check_box"
+    <CheckBox
+        android:id="@+id/check_box"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@string/hello_world" />
diff --git a/tests/tests/widget/res/layout/checkedtextview_layout.xml b/tests/tests/widget/res/layout/checkedtextview_layout.xml
index d5b9c1f..fbee93e 100644
--- a/tests/tests/widget/res/layout/checkedtextview_layout.xml
+++ b/tests/tests/widget/res/layout/checkedtextview_layout.xml
@@ -14,20 +14,22 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
-    <ListView android:id="@+id/checkedtextview_listview"
-        android:orientation="vertical"
+    <ListView
+        android:id="@+id/checkedtextview_listview"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    </ListView>
+        android:layout_height="0dip"
+        android:layout_weight="1" />
 
-    <CheckedTextView android:id="@+id/checkedtextview_test"
-        android:orientation="vertical"
+    <CheckedTextView
+        android:id="@+id/checkedtextview_test"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    </CheckedTextView>
+        android:layout_height="wrap_content"
+        android:text="@string/hello_world" />
 
 </LinearLayout>
diff --git a/tests/tests/widget/res/layout/datepicker_layout.xml b/tests/tests/widget/res/layout/datepicker_layout.xml
index 925674c..9857440 100644
--- a/tests/tests/widget/res/layout/datepicker_layout.xml
+++ b/tests/tests/widget/res/layout/datepicker_layout.xml
@@ -14,14 +14,29 @@
      limitations under the License.
 -->
 
-<RelativeLayout
+<ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <DatePicker
-        android:id="@+id/datePicker_dp"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true" />
+    android:layout_height="match_parent"
+    android:fillViewport="true">
 
-</RelativeLayout>
+    <LinearLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <DatePicker
+            android:id="@+id/date_picker_calendar_mode"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:datePickerMode="calendar" />
+
+        <DatePicker
+            android:id="@+id/date_picker_spinner_mode"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:datePickerMode="spinner" />
+
+    </LinearLayout>
+</ScrollView>
diff --git a/tests/tests/widget/res/layout/expandablelistview_child.xml b/tests/tests/widget/res/layout/expandablelistview_child.xml
new file mode 100644
index 0000000..b34f10b
--- /dev/null
+++ b/tests/tests/widget/res/layout/expandablelistview_child.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:textSize="18sp" />
diff --git a/tests/tests/widget/res/layout/expandablelistview_group.xml b/tests/tests/widget/res/layout/expandablelistview_group.xml
new file mode 100644
index 0000000..be929ee
--- /dev/null
+++ b/tests/tests/widget/res/layout/expandablelistview_group.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:textStyle="bold"
+    android:textSize="24sp" />
diff --git a/tests/tests/widget/res/layout/imagebutton_layout.xml b/tests/tests/widget/res/layout/imagebutton_layout.xml
new file mode 100644
index 0000000..f59f669
--- /dev/null
+++ b/tests/tests/widget/res/layout/imagebutton_layout.xml
@@ -0,0 +1,29 @@
+<?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.
+ -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <ImageButton
+        android:id="@+id/image_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/icon_red" />
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/imagebutton_test.xml b/tests/tests/widget/res/layout/imagebutton_test.xml
deleted file mode 100644
index 7d4b691..0000000
--- a/tests/tests/widget/res/layout/imagebutton_test.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2008 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.
- -->
-<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/imagebutton"
-    android:layout_width="96px"
-    android:layout_height="76px"
-    android:soundEffectsEnabled="false"
-/>
-
diff --git a/tests/tests/widget/res/layout/linearlayout_layout.xml b/tests/tests/widget/res/layout/linearlayout_layout.xml
index 8881552..11d2a71 100644
--- a/tests/tests/widget/res/layout/linearlayout_layout.xml
+++ b/tests/tests/widget/res/layout/linearlayout_layout.xml
@@ -14,125 +14,228 @@
  * 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:id="@+id/linearlayout_root"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/linearlayout_root"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
 
-    <LinearLayout android:id="@+id/horizontal"
-        android:orientation="horizontal"
+    <LinearLayout
+        android:id="@+id/horizontal"
         android:layout_width="wrap_content"
         android:layout_height="100dip"
-        android:background="#FF909090">
+        android:orientation="horizontal"
+        android:background="#888">
 
-        <TextView android:id="@+id/gravity_top"
-            android:background="#FF00FF00"
+        <TextView
+            android:id="@+id/gravity_top"
             android:layout_width="wrap_content"
             android:layout_height="50dip"
             android:layout_gravity="top"
-            android:text="@string/horizontal_text_1"/>
+            android:background="#0F0"
+            android:text="@string/horizontal_text_1" />
 
-        <TextView android:id="@+id/gravity_center_vertical"
-            android:background="#FF00FF00"
+        <TextView
+            android:id="@+id/gravity_center_vertical"
             android:layout_width="wrap_content"
             android:layout_height="50dip"
             android:layout_gravity="center_vertical"
-            android:text="@string/horizontal_text_2"/>
+            android:background="#0F0"
+            android:text="@string/horizontal_text_2" />
 
-        <TextView android:id="@+id/gravity_bottom"
-            android:background="#FF00FF00"
+        <TextView
+            android:id="@+id/gravity_bottom"
             android:layout_width="wrap_content"
             android:layout_height="50dip"
             android:layout_gravity="bottom"
-            android:text="@string/horizontal_text_3"/>
+            android:background="#0F0"
+            android:text="@string/horizontal_text_3" />
     </LinearLayout>
 
-    <LinearLayout android:id="@+id/vertical"
-        android:orientation="vertical"
+    <LinearLayout
+        android:id="@+id/vertical"
         android:layout_width="100dip"
         android:layout_height="wrap_content"
-        android:background="#FFFF0909">
+        android:orientation="vertical"
+        android:background="#F00">
 
-        <TextView android:id="@+id/gravity_left"
-            android:background="#FF00FF00"
+        <TextView
+            android:id="@+id/gravity_left"
             android:layout_width="wrap_content"
             android:layout_height="20dip"
             android:layout_gravity="left"
-            android:text="@string/vertical_text_1"/>
+            android:background="#0F0"
+            android:text="@string/vertical_text_1" />
 
-        <TextView android:id="@+id/gravity_center_horizontal"
-            android:background="#FF0000FF"
+        <TextView
+            android:id="@+id/gravity_center_horizontal"
             android:layout_width="wrap_content"
             android:layout_height="20dip"
             android:layout_gravity="center_horizontal"
-            android:text="@string/vertical_text_2"/>
+            android:background="#00F"
+            android:text="@string/vertical_text_2" />
 
-        <TextView android:id="@+id/gravity_right"
-            android:background="#FF00FF00"
+        <TextView
+            android:id="@+id/gravity_right"
             android:layout_width="wrap_content"
             android:layout_height="20dip"
             android:layout_gravity="right"
-            android:text="@string/vertical_text_3"/>
+            android:background="#0F0"
+            android:text="@string/vertical_text_3" />
     </LinearLayout>
 
-    <LinearLayout android:id="@+id/weightsum"
+    <LinearLayout
+        android:id="@+id/weightsum"
+        android:layout_width="100dip"
+        android:layout_height="100dip"
         android:orientation="horizontal"
         android:weightSum="1.0"
         android:baselineAligned="false"
-        android:layout_width="100dip"
-        android:layout_height="100dip"
-        android:background="#FF909090">
+        android:background="#888">
 
-        <TextView android:id="@+id/weight_0_2"
-            android:background="#FF0000FF"
+        <TextView
+            android:id="@+id/weight_0_2"
             android:layout_width="0dip"
             android:layout_height="wrap_content"
             android:layout_weight="0.2"
-            android:text="@string/horizontal_text_1"/>
+            android:background="#00F"
+            android:text="@string/horizontal_text_1" />
 
-        <TextView android:id="@+id/weight_0_5"
-            android:background="#FFF00F0F"
+        <TextView
+            android:id="@+id/weight_0_5"
             android:layout_width="0dip"
             android:layout_height="wrap_content"
             android:layout_weight="0.5"
-            android:text="@string/horizontal_text_2"/>
+            android:background="#F00"
+            android:text="@string/horizontal_text_2" />
 
-        <TextView android:id="@+id/weight_0_3"
-            android:background="#FF0000FF"
+        <TextView
+            android:id="@+id/weight_0_3"
             android:layout_width="0dip"
             android:layout_height="wrap_content"
             android:layout_weight="0.3"
-            android:text="@string/horizontal_text_3"/>
+            android:background="#00F"
+            android:text="@string/horizontal_text_3" />
     </LinearLayout>
 
-    <LinearLayout android:id="@+id/baseline_aligned_child_index"
+    <LinearLayout
+        android:id="@+id/weightsum_vertical"
+        android:layout_width="100dip"
+        android:layout_height="100dip"
         android:orientation="vertical"
-        android:baselineAlignedChildIndex="1"
+        android:weightSum="1.0"
+        android:baselineAligned="false"
+        android:background="#888">
+
+        <TextView
+            android:id="@+id/weight_0_1"
+            android:layout_width="wrap_content"
+            android:layout_height="0dip"
+            android:layout_weight="0.1"
+            android:background="#00F"
+            android:text="@string/vertical_text_1" />
+
+        <TextView
+            android:id="@+id/weight_0_4"
+            android:layout_width="wrap_content"
+            android:layout_height="0dip"
+            android:layout_weight="0.4"
+            android:background="#F00"
+            android:text="@string/vertical_text_2" />
+
+        <TextView
+            android:id="@+id/weight_0_5"
+            android:layout_width="wrap_content"
+            android:layout_height="0dip"
+            android:layout_weight="0.5"
+            android:background="#00F"
+            android:text="@string/vertical_text_3" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/baseline_aligned_child_index"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:background="#FFFF0909">
+        android:orientation="vertical"
+        android:baselineAlignedChildIndex="1"
+        android:background="#F00">
 
-        <TextView android:id="@+id/textview1"
-            android:background="#FF00FF00"
+        <TextView
+            android:id="@+id/textview1"
             android:layout_width="wrap_content"
             android:layout_height="20dip"
             android:layout_gravity="left"
-            android:text="@string/vertical_text_1"/>
+            android:background="#0F0"
+            android:text="@string/vertical_text_1" />
 
-        <TextView android:id="@+id/textview2"
-            android:background="#FF0000FF"
+        <TextView
+            android:id="@+id/textview2"
             android:layout_width="wrap_content"
             android:layout_height="20dip"
             android:layout_gravity="center_horizontal"
-            android:text="@string/vertical_text_2"/>
+            android:background="#00F"
+            android:text="@string/vertical_text_2" />
 
-        <TextView android:id="@+id/textview3"
-            android:background="#FF00FF00"
+        <TextView
+            android:id="@+id/textview3"
             android:layout_width="wrap_content"
             android:layout_height="20dip"
             android:layout_gravity="right"
-            android:text="@string/vertical_text_3"/>
+            android:background="#0F0"
+            android:text="@string/vertical_text_3" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/vertical_with_divider"
+        android:layout_width="100px"
+        android:layout_height="100px"
+        android:orientation="vertical"
+        android:background="#FF0"
+        android:showDividers="middle"
+        android:divider="@drawable/linear_layout_divider_red"
+        android:dividerPadding="@dimen/linear_layout_divider_padding">
+
+        <View
+            android:id="@+id/child1"
+            android:layout_width="match_parent"
+            android:layout_height="0dip"
+            android:layout_weight="0.5"
+            android:background="#00F" />
+
+        <View
+            android:id="@+id/child2"
+            android:layout_width="match_parent"
+            android:layout_height="0dip"
+            android:layout_weight="0.5"
+            android:background="#0F0" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/horizontal_with_divider"
+        android:layout_width="100px"
+        android:layout_height="100px"
+        android:orientation="horizontal"
+        android:background="#FF0"
+        android:showDividers="middle"
+        android:divider="@drawable/linear_layout_divider_red"
+        android:dividerPadding="@dimen/linear_layout_divider_padding">
+
+        <View
+            android:id="@+id/child1"
+            android:layout_width="0dip"
+            android:layout_height="match_parent"
+            android:layout_weight="0.5"
+            android:background="#00F" />
+
+        <View
+            android:id="@+id/child2"
+            android:layout_width="0dip"
+            android:layout_height="match_parent"
+            android:layout_weight="0.5"
+            android:background="#0F0" />
+
     </LinearLayout>
 
 </LinearLayout>
diff --git a/tests/tests/widget/res/layout/listitemfixed_layout.xml b/tests/tests/widget/res/layout/listitemfixed_layout.xml
new file mode 100644
index 0000000..395a547
--- /dev/null
+++ b/tests/tests/widget/res/layout/listitemfixed_layout.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="40px"
+    android:gravity="center_vertical"
+    android:textSize="36px"
+    android:textColor="#000" />
diff --git a/tests/tests/widget/res/layout/listview_layout.xml b/tests/tests/widget/res/layout/listview_layout.xml
index ee8b6de..3094a89 100644
--- a/tests/tests/widget/res/layout/listview_layout.xml
+++ b/tests/tests/widget/res/layout/listview_layout.xml
@@ -14,33 +14,48 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="match_parent">
 
-    <TextView android:id="@+id/headerview1"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/header_view" />
-
-    <TextView android:id="@+id/headerview2"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/header_view" />
-
-    <ListView android:id="@+id/listview_default"
+    <!-- This child is marked as GONE so that it won't interfere with the visuals of our
+         ListView on the screen. It's here to "hold" views that will be used as headers and
+         footers for the relevant tests. -->
+    <FrameLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
-
-    <TextView android:id="@+id/footerview1"
-        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:text="@string/footer_view" />
+        android:visibility="gone">
 
-    <TextView android:id="@+id/footerview2"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/footer_view" />
-</LinearLayout>
+        <TextView
+            android:id="@+id/headerview1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/header_view" />
+
+        <TextView
+            android:id="@+id/headerview2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/header_view" />
+
+        <TextView
+            android:id="@+id/footerview1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/footer_view" />
+
+        <TextView
+            android:id="@+id/footerview2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/footer_view" />
+    </FrameLayout>
+
+    <ListView
+        android:id="@+id/listview_default"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</FrameLayout>
 
diff --git a/tests/tests/widget/res/layout/listviewfixed_layout.xml b/tests/tests/widget/res/layout/listviewfixed_layout.xml
new file mode 100644
index 0000000..158ce99
--- /dev/null
+++ b/tests/tests/widget/res/layout/listviewfixed_layout.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ListView
+        android:id="@+id/listview_default"
+        android:layout_width="300px"
+        android:layout_height="300px"
+        android:divider="@null"
+        android:dividerHeight="0px"
+        android:background="#80FF0000"/>
+
+</FrameLayout>
+
diff --git a/tests/tests/widget/res/layout/numberpicker_layout.xml b/tests/tests/widget/res/layout/numberpicker_layout.xml
new file mode 100644
index 0000000..2e370d8
--- /dev/null
+++ b/tests/tests/widget/res/layout/numberpicker_layout.xml
@@ -0,0 +1,30 @@
+<?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
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <NumberPicker
+        android:id="@+id/number_picker"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/progressbar_layout.xml b/tests/tests/widget/res/layout/progressbar_layout.xml
index a1786b8..f242135 100644
--- a/tests/tests/widget/res/layout/progressbar_layout.xml
+++ b/tests/tests/widget/res/layout/progressbar_layout.xml
@@ -14,28 +14,47 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:fillViewport="true">
 
-    <ProgressBar
-        android:id="@+id/progress_tint"
-        android:progressTint="@android:color/white"
-        android:progressTintMode="src_over"
-        android:progressBackgroundTint="@android:color/white"
-        android:progressBackgroundTintMode="src_over"
-        android:secondaryProgressTint="@android:color/white"
-        android:secondaryProgressTintMode="src_over"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/Widget.ProgressBar.Horizontal" />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
 
-    <ProgressBar
-        android:id="@+id/indeterminate_tint"
-        android:indeterminateTint="@android:color/white"
-        android:indeterminateTintMode="src_over"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        style="@android:style/Widget.ProgressBar.Large" />
+        <ProgressBar
+            style="@android:style/Widget.Material.Light.ProgressBar"
+            android:id="@+id/progress"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
 
-</LinearLayout>
+        <ProgressBar
+            style="@android:style/Widget.Material.Light.ProgressBar.Horizontal"
+            android:id="@+id/progress_horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+        <ProgressBar
+            style="@android:style/Widget.Material.Light.ProgressBar.Horizontal"
+            android:id="@+id/progress_tint"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:progressTint="@android:color/white"
+            android:progressTintMode="src_over"
+            android:progressBackgroundTint="@android:color/white"
+            android:progressBackgroundTintMode="src_over"
+            android:secondaryProgressTint="@android:color/white"
+            android:secondaryProgressTintMode="src_over" />
+
+        <ProgressBar
+            style="@android:style/Widget.Material.Light.ProgressBar.Large"
+            android:id="@+id/indeterminate_tint"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:indeterminateTint="@android:color/white"
+            android:indeterminateTintMode="src_over" />
+
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/radiobutton_layout.xml b/tests/tests/widget/res/layout/radiobutton_layout.xml
new file mode 100644
index 0000000..23c1839
--- /dev/null
+++ b/tests/tests/widget/res/layout/radiobutton_layout.xml
@@ -0,0 +1,29 @@
+<?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.
+ -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <RadioButton
+        android:id="@+id/radio_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/hello_world" />
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/ratingbar_layout.xml b/tests/tests/widget/res/layout/ratingbar_layout.xml
index acc7fa8..b2fb4c7 100644
--- a/tests/tests/widget/res/layout/ratingbar_layout.xml
+++ b/tests/tests/widget/res/layout/ratingbar_layout.xml
@@ -14,18 +14,19 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:orientation="vertical">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
-    <RatingBar android:id="@+id/ratingbar_constructor"
+    <RatingBar
+        android:id="@+id/ratingbar_constructor"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:isIndicator="false"
         android:numStars="50"
         android:rating="1.2"
-        android:stepSize="0.2"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"/>
+        android:stepSize="0.2" />
 
 </LinearLayout>
diff --git a/tests/tests/widget/res/layout/remoteviews_adapter.xml b/tests/tests/widget/res/layout/remoteviews_adapter.xml
new file mode 100644
index 0000000..59115da
--- /dev/null
+++ b/tests/tests/widget/res/layout/remoteviews_adapter.xml
@@ -0,0 +1,39 @@
+<?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.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <StackView
+        android:id="@+id/remoteViews_stack"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:loopViews="true" />
+    <TextView
+        android:id="@+id/remoteViews_empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center" />
+    <ListView
+        android:id="@+id/remoteViews_list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone" />
+</FrameLayout>
+
+
diff --git a/tests/tests/widget/res/layout/remoteviews_adapter_item.xml b/tests/tests/widget/res/layout/remoteviews_adapter_item.xml
new file mode 100644
index 0000000..ec621da
--- /dev/null
+++ b/tests/tests/widget/res/layout/remoteviews_adapter_item.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/item"
+    android:layout_width="120dp"
+    android:layout_height="120dp"
+    android:gravity="center"
+    android:textStyle="bold"
+    android:textSize="44sp" />
diff --git a/tests/tests/widget/res/layout/remoteviews_extra.xml b/tests/tests/widget/res/layout/remoteviews_extra.xml
new file mode 100644
index 0000000..6a57ca3
--- /dev/null
+++ b/tests/tests/widget/res/layout/remoteviews_extra.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/remoteView_frame_extra"
+    android:layout_width="20dip"
+    android:layout_height="20dip" />
diff --git a/tests/tests/widget/res/layout/remoteviews_good.xml b/tests/tests/widget/res/layout/remoteviews_good.xml
index 8fdbc64..e322d0a 100644
--- a/tests/tests/widget/res/layout/remoteviews_good.xml
+++ b/tests/tests/widget/res/layout/remoteviews_good.xml
@@ -14,43 +14,79 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/remoteViews_good"
-    android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
 
-    <LinearLayout android:id="@+id/remoteView_linear"
+    <LinearLayout
+        android:id="@+id/remoteView_linear"
         android:layout_width="10dip"
         android:layout_height="10dip" />
 
-    <TextView android:id="@+id/remoteView_text"
+    <TextView
+        android:id="@+id/remoteView_label"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
 
-    <ImageView android:id="@+id/remoteView_image"
+    <TextView
+        android:id="@+id/remoteView_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
 
-    <FrameLayout android:id="@+id/remoteView_frame"
+    <TextView
+        android:id="@+id/remoteView_text_ltr"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layoutDirection="ltr" />
+
+    <TextView
+        android:id="@+id/remoteView_text_rtl"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layoutDirection="rtl" />
+
+    <ImageView
+        android:id="@+id/remoteView_image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <FrameLayout
+        android:id="@+id/remoteView_frame"
         android:layout_width="10dip"
         android:layout_height="10dip" />
 
-    <RelativeLayout android:id="@+id/remoteView_relative"
+    <RelativeLayout
+        android:id="@+id/remoteView_relative"
         android:layout_width="10dip"
         android:layout_height="10dip" />
 
-    <AbsoluteLayout android:id="@+id/remoteView_absolute"
+    <AbsoluteLayout
+        android:id="@+id/remoteView_absolute"
         android:layout_width="10dip"
         android:layout_height="10dip" />
 
-    <ProgressBar android:id="@+id/remoteView_progress"
+    <ProgressBar
+        android:id="@+id/remoteView_progress"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         style="?android:attr/progressBarStyleHorizontal" />
 
-    <Chronometer android:id="@+id/remoteView_chronometer"
+    <Chronometer
+        android:id="@+id/remoteView_chronometer"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
 
-</LinearLayout>
+    <StackView
+        android:id="@+id/remoteView_stack"
+        android:layout_width="100dip"
+        android:layout_height="100dip" />
+
+    <android.widget.cts.MyRemotableView
+        android:id="@+id/remoteView_custom"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/remoteviews_host.xml b/tests/tests/widget/res/layout/remoteviews_host.xml
index ace5903..ed0ba40 100644
--- a/tests/tests/widget/res/layout/remoteviews_host.xml
+++ b/tests/tests/widget/res/layout/remoteviews_host.xml
@@ -14,9 +14,9 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/remoteView_host"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:id="@+id/remoteView_host">
-</LinearLayout>
+    android:layout_height="match_parent">
+</FrameLayout>
diff --git a/tests/tests/widget/res/layout/searchview_layout.xml b/tests/tests/widget/res/layout/searchview_layout.xml
new file mode 100644
index 0000000..b8705e0
--- /dev/null
+++ b/tests/tests/widget/res/layout/searchview_layout.xml
@@ -0,0 +1,40 @@
+<?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
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <SearchView
+        android:id="@+id/search_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <SearchView
+        android:id="@+id/search_view_with_defaults"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:maxWidth="@dimen/search_view_max_width"
+        android:iconifiedByDefault="false"
+        android:queryHint="@string/search_query_hint"
+        android:inputType="textCapCharacters"
+        android:imeOptions="actionDone" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/searchview_suggestion_item.xml b/tests/tests/widget/res/layout/searchview_suggestion_item.xml
new file mode 100644
index 0000000..91f02f5
--- /dev/null
+++ b/tests/tests/widget/res/layout/searchview_suggestion_item.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/search_view_suggestion_row_height"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />
diff --git a/tests/tests/widget/res/layout/simple_spinner_item_layout.xml b/tests/tests/widget/res/layout/simple_spinner_item_layout.xml
new file mode 100644
index 0000000..512b138
--- /dev/null
+++ b/tests/tests/widget/res/layout/simple_spinner_item_layout.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    style="?android:attr/spinnerItemStyle"
+    android:singleLine="true"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:ellipsize="marquee"
+    android:textAlignment="inherit"/>
diff --git a/tests/tests/widget/res/layout/spinner_layout.xml b/tests/tests/widget/res/layout/spinner_layout.xml
new file mode 100644
index 0000000..43a6411
--- /dev/null
+++ b/tests/tests/widget/res/layout/spinner_layout.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true">
+
+    <LinearLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <Spinner
+            android:id="@+id/spinner_dropdown_mode"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:spinnerMode="dropdown"
+            android:prompt="@string/text_view_hello" />
+
+        <Spinner
+            android:id="@+id/spinner_dialog_mode"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:spinnerMode="dialog"
+            android:prompt="@string/text_view_hello" />
+
+    </LinearLayout>
+</ScrollView>
diff --git a/tests/tests/widget/res/layout/switch_layout.xml b/tests/tests/widget/res/layout/switch_layout.xml
index 12e10d2..880c6df 100644
--- a/tests/tests/widget/res/layout/switch_layout.xml
+++ b/tests/tests/widget/res/layout/switch_layout.xml
@@ -15,11 +15,31 @@
   ~ limitations under the License
   -->
 
-<Switch xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/switch_view"
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <Switch
+        android:id="@+id/switch1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:thumbTint="@android:color/white"
         android:thumbTintMode="src_over"
         android:trackTint="@android:color/black"
         android:trackTintMode="src_atop" />
+
+    <Switch
+        android:id="@+id/switch2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:thumb="@drawable/icon_blue"
+        android:track="@drawable/red_translucent_fill" />
+
+    <Switch
+        android:id="@+id/switch3"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/textview_layout.xml b/tests/tests/widget/res/layout/textview_layout.xml
index e3144eb..08354b1 100644
--- a/tests/tests/widget/res/layout/textview_layout.xml
+++ b/tests/tests/widget/res/layout/textview_layout.xml
@@ -14,209 +14,269 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:id="@+id/layout_textviewtest">
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scroller"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true">
 
-    <ScrollView android:layout_width="match_parent"
-            android:layout_height="match_parent">
+        <LinearLayout
+            android:id="@+id/layout_textviewtest"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
 
-        <LinearLayout android:orientation="vertical"
+            <TextView
+                android:id="@+id/textview_textAttr"
+                android:fontFamily="@null"
+                android:text="@string/text_view_hello"
+                android:textColor="@drawable/black"
+                android:textColorHighlight="@drawable/yellow"
+                android:textColorHint="@drawable/red"
+                android:textColorLink="@drawable/blue"
+                android:textScaleX="1.2"
+                android:typeface="normal"
+                android:textSize="20px"
+                android:textStyle="normal"
+                android:textAppearance="@null"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+
+            <TextView
+                android:id="@+id/textview_password"
+                android:password="true"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+
+            <TextView
+                android:id="@+id/textview_singleLine"
+                android:singleLine="true"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+
+            <TextView
+                android:id="@+id/textview_text"
+                android:text="@string/text_view_hello"
+                android:breakStrategy="simple"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+
+            <TextView
+                android:id="@+id/textview_text_two_lines"
+                android:text="@string/text_view_hello_two_lines"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+
+            <android.widget.cts.MockTextView
+                android:id="@+id/mock_textview_left"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:requiresFadingEdge="horizontal"
+                android:singleLine="true"
+                android:text="@string/long_text"
+                android:gravity="left" />
+
+            <android.widget.cts.MockTextView
+                android:id="@+id/mock_textview_right"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:requiresFadingEdge="horizontal"
+                android:singleLine="true"
+                android:text="@string/long_text"
+                android:gravity="right" />
+
+            <android.widget.cts.MockTextView
+                android:id="@+id/mock_textview_center"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:requiresFadingEdge="horizontal"
+                android:singleLine="true"
+                android:text="@string/long_text"
+                android:gravity="center" />
+
+            <TextView
+                android:id="@+id/textview_ltr"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"/>
+
+            <TextView
+                android:id="@+id/textview_rtl"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"/>
+
+            <TextView
+                android:id="@+id/textview_drawable_1_1"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:drawableLeft="@drawable/icon_blue"
+                android:drawableRight="@drawable/icon_red"
+                android:drawableTop="@drawable/icon_green"
+                android:drawableBottom="@drawable/icon_yellow"
+                android:layoutDirection="ltr" />
+
+            <TextView
+                android:id="@+id/textview_drawable_1_2"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:drawableLeft="@drawable/icon_blue"
+                android:drawableRight="@drawable/icon_red"
+                android:drawableTop="@drawable/icon_green"
+                android:drawableBottom="@drawable/icon_yellow"
+                android:layoutDirection="rtl" />
+
+            <TextView
+                android:id="@+id/textview_drawable_2_1"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:drawableStart="@drawable/icon_blue"
+                android:drawableEnd="@drawable/icon_red"
+                android:drawableTop="@drawable/icon_green"
+                android:drawableBottom="@drawable/icon_yellow"
+                android:layoutDirection="ltr" />
+
+            <TextView
+                android:id="@+id/textview_drawable_2_2"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:drawableStart="@drawable/icon_blue"
+                android:drawableEnd="@drawable/icon_red"
+                android:drawableTop="@drawable/icon_green"
+                android:drawableBottom="@drawable/icon_yellow"
+                android:layoutDirection="rtl" />
+
+            <TextView
+                android:id="@+id/textview_drawable_3_1"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:drawableLeft="@drawable/icon_black"
+                android:drawableRight="@drawable/icon_black"
+                android:drawableStart="@drawable/icon_blue"
+                android:drawableEnd="@drawable/icon_red"
+                android:drawableTop="@drawable/icon_green"
+                android:drawableBottom="@drawable/icon_yellow"
+                android:layoutDirection="ltr" />
+
+            <TextView
+                android:id="@+id/textview_drawable_3_2"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:drawableLeft="@drawable/icon_black"
+                android:drawableRight="@drawable/icon_black"
+                android:drawableStart="@drawable/icon_blue"
+                android:drawableEnd="@drawable/icon_red"
+                android:drawableTop="@drawable/icon_green"
+                android:drawableBottom="@drawable/icon_yellow"
+                android:layoutDirection="rtl" />
+
+            <LinearLayout
+                android:orientation="vertical"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent">
+                android:layout_height="wrap_content"
+                android:layoutDirection="ltr">
 
-            <TextView android:id="@+id/textview_textAttr"
-                    android:fontFamily="@null"
-                    android:text="@string/text_view_hello"
-                    android:textColor="@drawable/black"
-                    android:textColorHighlight="@drawable/yellow"
-                    android:textColorHint="@drawable/red"
-                    android:textColorLink="@drawable/blue"
-                    android:textScaleX="1.2"
-                    android:typeface="normal"
-                    android:textSize="20px"
-                    android:textStyle="normal"
-                    android:textAppearance="@null"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"/>
-
-            <TextView android:id="@+id/textview_password"
-                    android:password="true"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"/>
-
-            <TextView android:id="@+id/textview_singleLine"
-                    android:singleLine="true"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"/>
-
-            <TextView android:id="@+id/textview_text"
-                    android:text="@string/text_view_hello"
-                    android:breakStrategy="simple"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"/>
-
-            <TextView android:id="@+id/textview_text_two_lines"
-                    android:text="@string/text_view_hello_two_lines"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"/>
-
-            <android.widget.cts.MockTextView
-                    android:id="@+id/mock_textview_left"
-                    android:layout_width="wrap_content"
+                <TextView
+                    android:id="@+id/textview_drawable_4_1"
                     android:layout_height="wrap_content"
-                    android:requiresFadingEdge="horizontal"
-                    android:singleLine="true"
-                    android:text="@string/long_text"
-                    android:gravity="left"
-                    />
-
-            <android.widget.cts.MockTextView
-                    android:id="@+id/mock_textview_right"
                     android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:requiresFadingEdge="horizontal"
-                    android:singleLine="true"
-                    android:text="@string/long_text"
-                    android:gravity="right"
-                    />
+                    android:drawableStart="@drawable/icon_blue"
+                    android:drawableEnd="@drawable/icon_red"
+                    android:drawableTop="@drawable/icon_green"
+                    android:drawableBottom="@drawable/icon_yellow" />
 
-            <android.widget.cts.MockTextView
-                    android:id="@+id/mock_textview_center"
-                    android:layout_width="wrap_content"
+                <TextView
+                    android:id="@+id/textview_drawable_5_1"
                     android:layout_height="wrap_content"
-                    android:requiresFadingEdge="horizontal"
-                    android:singleLine="true"
-                    android:text="@string/long_text"
-                    android:gravity="center"
-                    />
+                    android:layout_width="wrap_content"
+                    android:drawableLeft="@drawable/icon_black"
+                    android:drawableRight="@drawable/icon_black"
+                    android:drawableStart="@drawable/icon_blue"
+                    android:drawableEnd="@drawable/icon_red"
+                    android:drawableTop="@drawable/icon_green"
+                    android:drawableBottom="@drawable/icon_yellow" />
+
+            </LinearLayout>
+
+            <LinearLayout
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layoutDirection="rtl">
+
+                <TextView
+                    android:id="@+id/textview_drawable_4_2"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:drawableStart="@drawable/icon_blue"
+                    android:drawableEnd="@drawable/icon_red"
+                    android:drawableTop="@drawable/icon_green"
+                    android:drawableBottom="@drawable/icon_yellow" />
+
+                <TextView
+                    android:id="@+id/textview_drawable_5_2"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:drawableLeft="@drawable/icon_black"
+                    android:drawableRight="@drawable/icon_black"
+                    android:drawableStart="@drawable/icon_blue"
+                    android:drawableEnd="@drawable/icon_red"
+                    android:drawableTop="@drawable/icon_green"
+                    android:drawableBottom="@drawable/icon_yellow" />
+
+            </LinearLayout>
+
+
+            <TextView
+                android:id="@+id/textview_compound_drawable_ltr"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:paddingLeft="@dimen/textview_padding_left"
+                android:paddingRight="@dimen/textview_padding_right"
+                android:paddingTop="@dimen/textview_padding_top"
+                android:paddingBottom="@dimen/textview_padding_bottom"
+                android:drawablePadding="@dimen/textview_drawable_padding"
+                android:drawableStart="@drawable/icon_blue"
+                android:drawableEnd="@drawable/icon_red"
+                android:drawableTop="@drawable/icon_green"
+                android:drawableBottom="@drawable/icon_yellow"
+                android:layoutDirection="ltr" />
+
+            <TextView
+                android:id="@+id/textview_compound_drawable_rtl"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:paddingLeft="@dimen/textview_padding_left"
+                android:paddingRight="@dimen/textview_padding_right"
+                android:paddingTop="@dimen/textview_padding_top"
+                android:paddingBottom="@dimen/textview_padding_bottom"
+                android:drawablePadding="@dimen/textview_drawable_padding"
+                android:drawableStart="@drawable/icon_blue"
+                android:drawableEnd="@drawable/icon_red"
+                android:drawableTop="@drawable/icon_green"
+                android:drawableBottom="@drawable/icon_yellow"
+                android:layoutDirection="rtl" />
+
+            <TextView
+                android:id="@+id/textview_with_shadow"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:text="@string/text_view_hello"
+                android:shadowDx="1.0"
+                android:shadowDy="2.0"
+                android:shadowRadius="3.0"
+                android:shadowColor="@color/testcolor1" />
+
+            <EditText
+                android:id="@+id/editview_text"
+                android:text="@string/text_view_hello"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+
+            <TextView
+                android:id="@+id/textview_pointer"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
         </LinearLayout>
 
-    </ScrollView>
-
-    <TextView android:id="@+id/textview_ltr"
-              android:layout_height="wrap_content"
-              android:layout_width="wrap_content"/>
-
-    <TextView android:id="@+id/textview_rtl"
-              android:layout_height="wrap_content"
-              android:layout_width="wrap_content"/>
-
-    <TextView android:id="@+id/textview_drawable_1_1"
-              android:layout_height="wrap_content"
-              android:layout_width="wrap_content"
-              android:drawableLeft="@drawable/icon_blue"
-              android:drawableRight="@drawable/icon_red"
-              android:drawableTop="@drawable/icon_green"
-              android:drawableBottom="@drawable/icon_yellow"
-            />
-
-    <TextView android:id="@+id/textview_drawable_1_2"
-              android:layout_height="wrap_content"
-              android:layout_width="wrap_content"
-              android:drawableLeft="@drawable/icon_blue"
-              android:drawableRight="@drawable/icon_red"
-              android:drawableTop="@drawable/icon_green"
-              android:drawableBottom="@drawable/icon_yellow"
-              android:layoutDirection="rtl"
-            />
-
-    <TextView android:id="@+id/textview_drawable_2_1"
-              android:layout_height="wrap_content"
-              android:layout_width="wrap_content"
-              android:drawableStart="@drawable/icon_blue"
-              android:drawableEnd="@drawable/icon_red"
-              android:drawableTop="@drawable/icon_green"
-              android:drawableBottom="@drawable/icon_yellow"
-            />
-
-    <TextView android:id="@+id/textview_drawable_2_2"
-              android:layout_height="wrap_content"
-              android:layout_width="wrap_content"
-              android:drawableStart="@drawable/icon_blue"
-              android:drawableEnd="@drawable/icon_red"
-              android:drawableTop="@drawable/icon_green"
-              android:drawableBottom="@drawable/icon_yellow"
-              android:layoutDirection="rtl"
-            />
-
-    <TextView android:id="@+id/textview_drawable_3_1"
-              android:layout_height="wrap_content"
-              android:layout_width="wrap_content"
-              android:drawableLeft="@drawable/icon_black"
-              android:drawableRight="@drawable/icon_black"
-              android:drawableStart="@drawable/icon_blue"
-              android:drawableEnd="@drawable/icon_red"
-              android:drawableTop="@drawable/icon_green"
-              android:drawableBottom="@drawable/icon_yellow"
-            />
-
-    <TextView android:id="@+id/textview_drawable_3_2"
-              android:layout_height="wrap_content"
-              android:layout_width="wrap_content"
-              android:drawableLeft="@drawable/icon_black"
-              android:drawableRight="@drawable/icon_black"
-              android:drawableStart="@drawable/icon_blue"
-              android:drawableEnd="@drawable/icon_red"
-              android:drawableTop="@drawable/icon_green"
-              android:drawableBottom="@drawable/icon_yellow"
-              android:layoutDirection="rtl"
-            />
-
-
-    <LinearLayout android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="match_parent"
-                  android:layoutDirection="ltr">
-
-        <TextView android:id="@+id/textview_drawable_4_1"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:drawableStart="@drawable/icon_blue"
-                  android:drawableEnd="@drawable/icon_red"
-                  android:drawableTop="@drawable/icon_green"
-                  android:drawableBottom="@drawable/icon_yellow"
-                />
-
-        <TextView android:id="@+id/textview_drawable_5_1"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:drawableLeft="@drawable/icon_black"
-                  android:drawableRight="@drawable/icon_black"
-                  android:drawableStart="@drawable/icon_blue"
-                  android:drawableEnd="@drawable/icon_red"
-                  android:drawableTop="@drawable/icon_green"
-                  android:drawableBottom="@drawable/icon_yellow"
-                />
-
-    </LinearLayout>
-
-    <LinearLayout android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="match_parent"
-                  android:layoutDirection="rtl">
-
-        <TextView android:id="@+id/textview_drawable_4_2"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:drawableStart="@drawable/icon_blue"
-                  android:drawableEnd="@drawable/icon_red"
-                  android:drawableTop="@drawable/icon_green"
-                  android:drawableBottom="@drawable/icon_yellow"
-                />
-
-        <TextView android:id="@+id/textview_drawable_5_2"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:drawableLeft="@drawable/icon_black"
-                  android:drawableRight="@drawable/icon_black"
-                  android:drawableStart="@drawable/icon_blue"
-                  android:drawableEnd="@drawable/icon_red"
-                  android:drawableTop="@drawable/icon_green"
-                  android:drawableBottom="@drawable/icon_yellow"
-                />
-
-    </LinearLayout>
-
-</LinearLayout>
+</ScrollView>
diff --git a/tests/tests/widget/res/layout/timepicker.xml b/tests/tests/widget/res/layout/timepicker.xml
index 352f69b..c545eba 100644
--- a/tests/tests/widget/res/layout/timepicker.xml
+++ b/tests/tests/widget/res/layout/timepicker.xml
@@ -14,6 +14,17 @@
      limitations under the License.
 -->
 
-<TimePicker xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"/>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+    <TimePicker
+            android:id="@+id/timepicker_clock"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+    <TimePicker
+            android:id="@+id/timepicker_spinner"
+            android:datePickerMode="spinner"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/togglebutton_layout.xml b/tests/tests/widget/res/layout/togglebutton_layout.xml
index a6c08e1..de2faf3 100644
--- a/tests/tests/widget/res/layout/togglebutton_layout.xml
+++ b/tests/tests/widget/res/layout/togglebutton_layout.xml
@@ -15,8 +15,8 @@
  * limitations under the License.
  -->
 
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
@@ -25,19 +25,35 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
 
-        <ToggleButton android:id="@+id/toggle1"
+        <ToggleButton
+            android:id="@+id/toggle1"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content" />
 
-        <ToggleButton android:id="@+id/toggle2"
+        <ToggleButton
+            android:id="@+id/toggle2"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content" />
 
-        <ToggleButton android:id="@+id/button_tint"
+        <ToggleButton
+            android:id="@+id/toggle_with_defaults"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textOn="@string/toggle_text_on_alt"
+            android:textOff="@string/toggle_text_off_alt" />
+
+        <ToggleButton
+            style="@style/Theme_Toggle"
+            android:id="@+id/toggle_with_style"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <ToggleButton
+            android:id="@+id/button_tint"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:buttonTint="@android:color/white"
-            android:buttonTintMode="src_over"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+            android:buttonTintMode="src_over" />
 
     </LinearLayout>
 
diff --git a/tests/tests/widget/res/layout/zoombutton_layout.xml b/tests/tests/widget/res/layout/zoombutton_layout.xml
index 1b1e0b2..49031a8 100644
--- a/tests/tests/widget/res/layout/zoombutton_layout.xml
+++ b/tests/tests/widget/res/layout/zoombutton_layout.xml
@@ -14,9 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  -->
-<ZoomButton xmlns:android="http://schemas.android.com/apk/res/android"
+<ZoomButton
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/zoombutton_test"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-/>
+    android:src="@drawable/icon_red" />
 
diff --git a/tests/tests/widget/res/menu/cab_menu.xml b/tests/tests/widget/res/menu/cab_menu.xml
new file mode 100644
index 0000000..7e210cb
--- /dev/null
+++ b/tests/tests/widget/res/menu/cab_menu.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 Google Inc.
+
+     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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/action_highlight"
+          android:title="@string/popup_menu_highlight"
+          android:icon="@drawable/ic_highlight"
+          android:showAsAction="always" />
+    <item android:id="@+id/action_delete"
+          android:title="@string/popup_menu_delete"
+          android:icon="@drawable/ic_delete"
+          android:showAsAction="always" />
+</menu>
diff --git a/tests/tests/widget/res/values/attrs.xml b/tests/tests/widget/res/values/attrs.xml
index 4c3d9db..b2bea6f 100644
--- a/tests/tests/widget/res/values/attrs.xml
+++ b/tests/tests/widget/res/values/attrs.xml
@@ -142,4 +142,7 @@
     <attr name="themeGravity" />
     <attr name="themeTileMode" />
     <attr name="themeAngle" />
+
+    <attr name="chronometerStyle" format="string" />
+
 </resources>
diff --git a/tests/tests/widget/res/values/dimens.xml b/tests/tests/widget/res/values/dimens.xml
index 3690039..7cbff3a 100644
--- a/tests/tests/widget/res/values/dimens.xml
+++ b/tests/tests/widget/res/values/dimens.xml
@@ -15,4 +15,33 @@
 -->
 <resources>
     <dimen name="popup_row_height">48dp</dimen>
+
+    <dimen name="switch_padding">24dp</dimen>
+    <dimen name="switch_thumb_text_padding">12dp</dimen>
+    <dimen name="switch_min_width">160dp</dimen>
+    <dimen name="switch_min_width2">200dp</dimen>
+
+    <dimen name="autocomplete_textview_dropdown_height">120dp</dimen>
+    <dimen name="autocomplete_textview_dropdown_width">160dp</dimen>
+    <dimen name="autocomplete_textview_dropdown_offset_h">24dp</dimen>
+    <dimen name="autocomplete_textview_dropdown_offset_v">32dp</dimen>
+
+    <dimen name="spinner_dropdown_width">200dp</dimen>
+    <dimen name="spinner_dropdown_offset_h">64dp</dimen>
+    <dimen name="spinner_dropdown_offset_v">48dp</dimen>
+
+    <dimen name="search_view_max_width">160dp</dimen>
+    <dimen name="search_view_max_width2">200dp</dimen>
+    <dimen name="search_view_suggestion_row_height">48dp</dimen>
+
+    <dimen name="linear_layout_divider_size">10px</dimen>
+    <dimen name="linear_layout_divider_padding">8px</dimen>
+
+    <dimen name="textview_padding_left">4dip</dimen>
+    <dimen name="textview_padding_right">6dip</dimen>
+    <dimen name="textview_padding_start">8dip</dimen>
+    <dimen name="textview_padding_end">10dip</dimen>
+    <dimen name="textview_padding_top">2dip</dimen>
+    <dimen name="textview_padding_bottom">4dip</dimen>
+    <dimen name="textview_drawable_padding">2dip</dimen>
 </resources>
\ No newline at end of file
diff --git a/tests/tests/widget/res/values/strings.xml b/tests/tests/widget/res/values/strings.xml
index 63ceffa..3820072 100644
--- a/tests/tests/widget/res/values/strings.xml
+++ b/tests/tests/widget/res/values/strings.xml
@@ -193,4 +193,15 @@
     <string name="toolbar_subtitle">Toolbar subtitle</string>
     <string name="toolbar_navigation">Toolbar navigation</string>
     <string name="toolbar_logo">Toolbar logo</string>
+
+    <string name="search_query_hint">query hint</string>
+
+    <string name="remote_content_description">remote description</string>
+
+    <string name="toggle_text_on">On</string>
+    <string name="toggle_text_off">Off</string>
+    <string name="toggle_text_on_alt">On Alt</string>
+    <string name="toggle_text_off_alt">Off Alt</string>
+
+    <string name="chronometer_format">Current count: %s</string>
 </resources>
diff --git a/tests/tests/widget/res/values/styles.xml b/tests/tests/widget/res/values/styles.xml
index 345b450..bddc891 100644
--- a/tests/tests/widget/res/values/styles.xml
+++ b/tests/tests/widget/res/values/styles.xml
@@ -202,4 +202,19 @@
     </style>
 
     <style name="ToolbarPopupTheme_Test" parent="@android:style/ThemeOverlay.Material.Light" />
+
+    <style name="Theme_Toggle" parent="@android:style/Widget.Material.Light.Button.Toggle">
+        <item name="android:textOn">@string/toggle_text_on</item>
+        <item name="android:textOff">@string/toggle_text_off</item>
+    </style>
+
+    <style name="ChronometerStyle" parent="@android:style/Widget.Material.Light.TextView">
+        <item name="android:format">@string/chronometer_format</item>
+        <item name="android:countDown">true</item>
+    </style>
+
+    <style name="ChronometerAwareTheme" parent="@android:style/Theme.Material.Light">
+        <item name="chronometerStyle">@style/ChronometerStyle</item>
+    </style>
+
 </resources>
diff --git a/tests/tests/widget/res/xml/remoteviews_appwidget_info.xml b/tests/tests/widget/res/xml/remoteviews_appwidget_info.xml
new file mode 100644
index 0000000..e75ed72
--- /dev/null
+++ b/tests/tests/widget/res/xml/remoteviews_appwidget_info.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<appwidget-provider
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:minWidth="200dp"
+    android:minHeight="200dp"
+    android:minResizeWidth="300dp"
+    android:minResizeHeight="300dp"
+    android:updatePeriodMillis="86400000"
+    android:initialLayout="@layout/remoteviews_adapter"
+    android:resizeMode="horizontal|vertical"
+    android:widgetCategory="home_screen|keyguard"
+    android:previewImage="@drawable/icon_red">
+</appwidget-provider>
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
index cf8012e..4e5d1a1 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
@@ -16,99 +16,134 @@
 
 package android.widget.cts;
 
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.cts.util.CtsTouchUtils;
 import android.cts.util.PollingCheck;
 import android.cts.util.WidgetTestUtils;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.text.Editable;
 import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Xml;
+import android.view.ActionMode;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AbsListView;
 import android.widget.AbsListView.OnScrollListener;
-import android.widget.AbsListView.RecyclerListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.TextView;
+import android.widget.cts.util.TestUtils;
+import android.widget.cts.util.TestUtilsMatchers;
+
+import org.hamcrest.MatcherAssert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
-public class AbsListViewTest extends ActivityInstrumentationTestCase2<ListViewCtsActivity> {
-    private final String[] mShortList = new String[] {
-        "This", "is", "short", "!",
-    };
-    private final String[] mCountryList = new String[] {
-        "Argentina", "Australia", "China", "France", "Germany", "Italy", "Japan", "United States",
-        "Argentina", "Australia", "China", "France", "Germany", "Italy", "Japan", "United States",
-        "Argentina", "Australia", "China", "France", "Germany", "Italy", "Japan", "United States"
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AbsListViewTest {
+    private static final String[] SHORT_LIST = new String[] { "This", "is", "short", "!" };
+
+    private static final String[] COUNTRY_LIST = new String[] {
+            "Argentina", "Armenia", "Aruba", "Australia", "Belarus", "Belgium", "Belize", "Benin",
+            "Botswana", "Brazil", "Cameroon", "China", "Colombia", "Costa Rica", "Cyprus",
+            "Denmark", "Djibouti", "Ethiopia", "Fiji", "Finland", "France", "Gabon", "Germany",
+            "Ghana", "Haiti", "Honduras", "Iceland", "India", "Indonesia", "Ireland", "Italy",
+            "Japan", "Kiribati", "Laos", "Lesotho", "Liberia", "Malaysia", "Mongolia", "Myanmar",
+            "Nauru", "Norway", "Oman", "Pakistan", "Philippines", "Portugal", "Romania", "Russia",
+            "Rwanda", "Singapore", "Slovakia", "Slovenia", "Somalia", "Swaziland", "Togo", "Tuvalu",
+            "Uganda", "Ukraine", "United States", "Vanuatu", "Venezuela", "Zimbabwe"
     };
 
-    private ListView mListView;
-    private Activity mActivity;
+    @Rule
+    public ActivityTestRule<ListViewCtsActivity> mActivityRule
+            = new ActivityTestRule<>(ListViewCtsActivity.class);
+
+    private AbsListView mListView;
+    private Context mContext;
     private Instrumentation mInstrumentation;
     private AttributeSet mAttributeSet;
-    private ArrayAdapter<String> mAdapter_short;
-    private ArrayAdapter<String> mAdapter_countries;
+    private ArrayAdapter<String> mShortAdapter;
+    private ArrayAdapter<String> mCountriesAdapter;
+    private AbsListView.MultiChoiceModeListener mMultiChoiceModeListener;
 
     private static final float DELTA = 0.001f;
 
-    public AbsListViewTest() {
-        super("android.widget.cts", ListViewCtsActivity.class);
-    }
+    @Before
+    public void setup() throws Exception {
 
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+        final Activity activity = mActivityRule.getActivity();
 
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
-        mInstrumentation = getInstrumentation();
+        PollingCheck.waitFor(activity::hasWindowFocus);
 
-        XmlPullParser parser = mActivity.getResources().getXml(R.layout.listview_layout);
-        WidgetTestUtils.beginDocument(parser, "LinearLayout");
+        XmlPullParser parser = mContext.getResources().getXml(R.layout.listview_layout);
+        WidgetTestUtils.beginDocument(parser, "FrameLayout");
         mAttributeSet = Xml.asAttributeSet(parser);
 
-        mAdapter_short = new ArrayAdapter<String>(mActivity,
-                android.R.layout.simple_list_item_1, mShortList);
-        mAdapter_countries = new ArrayAdapter<String>(mActivity,
-                android.R.layout.simple_list_item_1, mCountryList);
+        mShortAdapter = new ArrayAdapter<>(mContext,
+                android.R.layout.simple_list_item_1, SHORT_LIST);
+        mCountriesAdapter = new ArrayAdapter<>(mContext,
+                android.R.layout.simple_list_item_1, COUNTRY_LIST);
 
-        mListView = (ListView)mActivity.findViewById(R.id.listview_default);
+        mListView = (ListView) activity.findViewById(R.id.listview_default);
     }
 
-    public void testConstructor() {
-        /**
-         * We can not test the constructors.
-         */
-    }
-
+    @Test
     public void testAccessFastScrollEnabled() {
         mListView.setFastScrollEnabled(false);
         assertFalse(mListView.isFastScrollEnabled());
@@ -117,6 +152,7 @@
         assertTrue(mListView.isFastScrollEnabled());
     }
 
+    @Test
     public void testAccessSmoothScrollbarEnabled() {
         mListView.setSmoothScrollbarEnabled(false);
         assertFalse(mListView.isSmoothScrollbarEnabled());
@@ -125,6 +161,7 @@
         assertTrue(mListView.isSmoothScrollbarEnabled());
     }
 
+    @Test
     public void testAccessScrollingCacheEnabled() {
         mListView.setScrollingCacheEnabled(false);
         assertFalse(mListView.isScrollingCacheEnabled());
@@ -133,117 +170,128 @@
         assertTrue(mListView.isScrollingCacheEnabled());
     }
 
-    private void setAdapter() throws Throwable {
-        setAdapter(mAdapter_countries);
+    private void setAdapter() {
+        setAdapter(mCountriesAdapter);
     }
 
-    private void setAdapter(final ListAdapter adapter) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.setAdapter(adapter);
-            }
-        });
+    private void setAdapter(final ListAdapter adapter) {
+        mInstrumentation.runOnMainSync(() -> mListView.setAdapter(adapter));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setListSelection(int index) throws Throwable {
-        final int i = index;
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.setSelection(i);
-            }
-        });
+    private void setListSelection(int index) {
+        mInstrumentation.runOnMainSync(() -> mListView.setSelection(index));
         mInstrumentation.waitForIdleSync();
     }
-    public void testSetOnScrollListener() throws Throwable {
-        MockOnScrollListener onScrollListener = new MockOnScrollListener();
 
-        assertNull(onScrollListener.getView());
-        assertEquals(0, onScrollListener.getFirstVisibleItem());
-        assertEquals(0, onScrollListener.getVisibleItemCount());
-        assertEquals(0, onScrollListener.getTotalItemCount());
-        assertEquals(-1, onScrollListener.getScrollState());
+    @LargeTest
+    @Test
+    public void testSetOnScrollListener() {
+        AbsListView.OnScrollListener mockScrollListener =
+                mock(AbsListView.OnScrollListener.class);
 
-        assertFalse(onScrollListener.isOnScrollCalled());
-        assertFalse(onScrollListener.isOnScrollStateChangedCalled());
+        verifyZeroInteractions(mockScrollListener);
 
-        mListView.setOnScrollListener(onScrollListener);
-        assertSame(mListView, onScrollListener.getView());
-        assertEquals(0, onScrollListener.getFirstVisibleItem());
-        assertEquals(0, onScrollListener.getVisibleItemCount());
-        assertEquals(0, onScrollListener.getTotalItemCount());
-        assertEquals(-1, onScrollListener.getScrollState());
+        mListView.setOnScrollListener(mockScrollListener);
+        verify(mockScrollListener, times(1)).onScroll(mListView, 0, 0, 0);
+        verifyNoMoreInteractions(mockScrollListener);
 
-        assertTrue(onScrollListener.isOnScrollCalled());
-        assertFalse(onScrollListener.isOnScrollStateChangedCalled());
-        onScrollListener.reset();
+        reset(mockScrollListener);
 
         setAdapter();
+        verify(mockScrollListener, times(1)).onScroll(mListView, 0, mListView.getChildCount(),
+                COUNTRY_LIST.length);
+        verifyNoMoreInteractions(mockScrollListener);
 
-        assertSame(mListView, onScrollListener.getView());
-        assertEquals(0, onScrollListener.getFirstVisibleItem());
-        assertEquals(mListView.getChildCount(), onScrollListener.getVisibleItemCount());
-        assertEquals(mCountryList.length, onScrollListener.getTotalItemCount());
-        assertEquals(-1, onScrollListener.getScrollState());
+        reset(mockScrollListener);
 
-        assertTrue(onScrollListener.isOnScrollCalled());
-        assertFalse(onScrollListener.isOnScrollStateChangedCalled());
-        onScrollListener.reset();
+        CtsTouchUtils.emulateScrollToBottom(mInstrumentation, mListView);
 
-        TouchUtils.scrollToBottom(this, mActivity, mListView);
-        assertSame(mListView, onScrollListener.getView());
-        assertEquals(mListView.getChildCount(), onScrollListener.getVisibleItemCount());
-        assertEquals(mCountryList.length, onScrollListener.getTotalItemCount());
+        ArgumentCaptor<Integer> firstVisibleItemCaptor = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Integer> visibleItemCountCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mockScrollListener, atLeastOnce()).onScroll(eq(mListView),
+                firstVisibleItemCaptor.capture(), visibleItemCountCaptor.capture(),
+                eq(COUNTRY_LIST.length));
 
-        assertTrue(onScrollListener.isOnScrollCalled());
-        assertTrue(onScrollListener.isOnScrollStateChangedCalled());
+        // We expect the first visible item values to be increasing
+        MatcherAssert.assertThat(firstVisibleItemCaptor.getAllValues(),
+                TestUtilsMatchers.inAscendingOrder());
+        // The number of visible items during scrolling may change depending on the specific
+        // scroll position. As such we only test this number at the very end
+        final List<Integer> capturedVisibleItemCounts = visibleItemCountCaptor.getAllValues();
+        assertEquals(mListView.getChildCount(),
+                (int) capturedVisibleItemCounts.get(capturedVisibleItemCounts.size() - 1));
+
+        ArgumentCaptor<Integer> scrollStateCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mockScrollListener, atLeastOnce()).onScrollStateChanged(eq(mListView),
+                scrollStateCaptor.capture());
+
+        // Verify that the last scroll state is IDLE
+        final List<Integer> capturedScrollStates = scrollStateCaptor.getAllValues();
+        assertEquals(AbsListView.OnScrollListener.SCROLL_STATE_IDLE,
+                (int) capturedScrollStates.get(capturedScrollStates.size() - 1));
     }
 
-    public void testFling() throws Throwable {
-        MockOnScrollListener onScrollListener = new MockOnScrollListener();
-        mListView.setOnScrollListener(onScrollListener);
+    @LargeTest
+    @Test
+    public void testFling() {
+        AbsListView.OnScrollListener mockScrollListener = mock(AbsListView.OnScrollListener.class);
+        mListView.setOnScrollListener(mockScrollListener);
 
         setAdapter();
 
         // Fling down from top, expect a scroll.
-        fling(10000, onScrollListener);
-        assertTrue(onScrollListener.isOnScrollCalled());
-        assertTrue(0 < onScrollListener.getFirstVisibleItem());
+        fling(10000, mockScrollListener);
+        ArgumentCaptor<Integer> firstVisibleItemCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mockScrollListener, atLeastOnce()).onScroll(eq(mListView),
+                firstVisibleItemCaptor.capture(), anyInt(), eq(COUNTRY_LIST.length));
+        List<Integer> capturedFirstVisibleItems = firstVisibleItemCaptor.getAllValues();
+        assertTrue(capturedFirstVisibleItems.get(capturedFirstVisibleItems.size() - 1) > 0);
 
         // Fling up the same amount, expect a scroll to the original position.
-        fling(-10000, onScrollListener);
-        assertTrue(onScrollListener.isOnScrollCalled());
-        assertEquals(0, onScrollListener.getFirstVisibleItem());
+        fling(-10000, mockScrollListener);
+        firstVisibleItemCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mockScrollListener, atLeastOnce()).onScroll(eq(mListView),
+                firstVisibleItemCaptor.capture(), anyInt(), eq(COUNTRY_LIST.length));
+        capturedFirstVisibleItems = firstVisibleItemCaptor.getAllValues();
+        assertTrue(capturedFirstVisibleItems.get(capturedFirstVisibleItems.size() - 1) == 0);
 
         // Fling up again, expect no scroll, as the viewport is already at top.
-        fling(-10000, onScrollListener);
-        assertFalse(onScrollListener.isOnScrollCalled());
-        assertEquals(0, onScrollListener.getFirstVisibleItem());
+        fling(-10000, mockScrollListener);
+        verify(mockScrollListener, never()).onScroll(any(AbsListView.class), anyInt(), anyInt(),
+                anyInt());
 
         // Fling up again with a huge velocity, expect no scroll.
-        fling(-50000, onScrollListener);
-        assertFalse(onScrollListener.isOnScrollCalled());
-        assertEquals(0, onScrollListener.getFirstVisibleItem());
+        fling(-50000, mockScrollListener);
+        verify(mockScrollListener, never()).onScroll(any(AbsListView.class), anyInt(), anyInt(),
+                anyInt());
     }
 
-    private void fling(int velocityY, MockOnScrollListener onScrollListener) throws Throwable {
-        onScrollListener.reset();
+    private void fling(int velocityY, OnScrollListener mockScrollListener) {
+        reset(mockScrollListener);
 
-        final int v = velocityY;
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.fling(v);
-            }
-        });
+        // Create a count down latch and configure it to be counted down when our mock
+        // listener is invoked with IDLE state
+        final CountDownLatch countDownLatch = new CountDownLatch(1);
+        doAnswer((InvocationOnMock invocation) -> {
+             countDownLatch.countDown();
+             return null;
+        }).when(mockScrollListener).onScrollStateChanged(
+                mListView, OnScrollListener.SCROLL_STATE_IDLE);
 
-        do {
-            mInstrumentation.waitForIdleSync();
-        } while (onScrollListener.getScrollState() != OnScrollListener.SCROLL_STATE_IDLE);
+        // Now fling the list view
+        mInstrumentation.runOnMainSync(() -> mListView.fling(velocityY));
+
+        // And wait for the latch to be triggered
+        try {
+            assertTrue(countDownLatch.await(20L, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+        }
     }
 
-    public void testGetFocusedRect() throws Throwable {
-        setAdapter(mAdapter_short);
+    @Test
+    public void testGetFocusedRect() {
+        setAdapter(mShortAdapter);
         setListSelection(0);
 
         Rect r1 = new Rect();
@@ -267,46 +315,48 @@
         assertEquals(r1.right, r2.right);
     }
 
-    public void testAccessStackFromBottom() throws Throwable {
+    @Test
+    public void testAccessStackFromBottom() {
         setAdapter();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.setStackFromBottom(false);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setStackFromBottom(false));
         assertFalse(mListView.isStackFromBottom());
         assertEquals(0, mListView.getSelectedItemPosition());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.setStackFromBottom(true);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setStackFromBottom(true));
 
         mInstrumentation.waitForIdleSync();
         assertTrue(mListView.isStackFromBottom());
         // ensure last item in list is selected
-        assertEquals(mCountryList.length-1, mListView.getSelectedItemPosition());
+        assertEquals(COUNTRY_LIST.length-1, mListView.getSelectedItemPosition());
     }
 
-    public void testAccessSelectedItem() throws Throwable {
+    @Test
+    public void testAccessSelectedItem() {
         assertNull(mListView.getSelectedView());
 
         setAdapter();
+
+        final int lastVisiblePosition = mListView.getLastVisiblePosition();
+
         TextView tv = (TextView) mListView.getSelectedView();
-        assertEquals(mCountryList[0], tv.getText().toString());
+        assertEquals(COUNTRY_LIST[0], tv.getText().toString());
 
-        setListSelection(5);
-        tv = (TextView) mListView.getSelectedView();
-        assertEquals(mCountryList[5], tv.getText().toString());
+        if (lastVisiblePosition >= 5) {
+            setListSelection(5);
+            tv = (TextView) mListView.getSelectedView();
+            assertEquals(COUNTRY_LIST[5], tv.getText().toString());
+        }
 
-        setListSelection(2);
-        tv = (TextView) mListView.getSelectedView();
-        assertEquals(mCountryList[2], tv.getText().toString());
+        if (lastVisiblePosition >= 2) {
+            setListSelection(2);
+            tv = (TextView) mListView.getSelectedView();
+            assertEquals(COUNTRY_LIST[2], tv.getText().toString());
+        }
     }
 
-    public void testAccessListPadding() throws Throwable {
+    @Test
+    public void testAccessListPadding() {
         setAdapter();
 
         assertEquals(0, mListView.getListPaddingLeft());
@@ -315,11 +365,8 @@
         assertEquals(0, mListView.getListPaddingBottom());
 
         final Rect r = new Rect(0, 0, 40, 60);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.setPadding(r.left, r.top, r.right, r.bottom);
-            }
-        });
+        mInstrumentation.runOnMainSync(
+                () -> mListView.setPadding(r.left, r.top, r.right, r.bottom));
         mInstrumentation.waitForIdleSync();
 
         assertEquals(r.left, mListView.getListPaddingLeft());
@@ -328,17 +375,14 @@
         assertEquals(r.bottom, mListView.getListPaddingBottom());
     }
 
-    public void testAccessSelector() throws Throwable {
+    @Test
+    public void testAccessSelector() {
         setAdapter();
 
-        final Drawable d = mActivity.getResources().getDrawable(R.drawable.pass);
+        final Drawable d = mContext.getDrawable(R.drawable.pass);
         mListView.setSelector(d);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.requestLayout();
-            }
-        });
+        mInstrumentation.runOnMainSync(mListView::requestLayout);
         mInstrumentation.waitForIdleSync();
         assertSame(d, mListView.getSelector());
         assertTrue(mListView.verifyDrawable(d));
@@ -346,11 +390,7 @@
         mListView.setSelector(R.drawable.failed);
         mListView.setDrawSelectorOnTop(true);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.requestLayout();
-            }
-        });
+        mInstrumentation.runOnMainSync(mListView::requestLayout);
         mInstrumentation.waitForIdleSync();
 
         Drawable drawable = mListView.getSelector();
@@ -358,34 +398,28 @@
         final Rect r = drawable.getBounds();
 
         final TextView v = (TextView) mListView.getSelectedView();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return v.getRight() == r.right;
-            }
-        }.run();
+        PollingCheck.waitFor(() -> v.getRight() == r.right);
         assertEquals(v.getLeft(), r.left);
         assertEquals(v.getTop(), r.top);
         assertEquals(v.getBottom(), r.bottom);
     }
 
-    public void testSetScrollIndicators() throws Throwable {
-        TextView tv1 = (TextView) mActivity.findViewById(R.id.headerview1);
-        TextView tv2 = (TextView) mActivity.findViewById(R.id.footerview1);
+    @Test
+    public void testSetScrollIndicators() {
+        final Activity activity = mActivityRule.getActivity();
+        TextView tv1 = (TextView) activity.findViewById(R.id.headerview1);
+        TextView tv2 = (TextView) activity.findViewById(R.id.footerview1);
 
         setAdapter();
 
         mListView.setScrollIndicators(tv1, tv2);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.requestLayout();
-            }
-        });
+        mInstrumentation.runOnMainSync(mListView::requestLayout);
         mInstrumentation.waitForIdleSync();
     }
 
-    public void testShowContextMenuForChild() throws Throwable {
+    @Test
+    public void testShowContextMenuForChild() {
         setAdapter();
         setListSelection(1);
 
@@ -395,7 +429,8 @@
         // TODO: how to show the contextMenu success
     }
 
-    public void testPointToPosition() throws Throwable {
+    @Test
+    public void testPointToPosition() {
         assertEquals(AbsListView.INVALID_POSITION, mListView.pointToPosition(-1, -1));
         assertEquals(AbsListView.INVALID_ROW_ID, mListView.pointToRowId(-1, -1));
 
@@ -408,39 +443,37 @@
         int position1 = mListView.pointToPosition(0, 0);
         int position2 = mListView.pointToPosition(50, middleOfSecondRow);
 
-        assertEquals(mAdapter_countries.getItemId(position1), mListView.pointToRowId(0, 0));
-        assertEquals(mAdapter_countries.getItemId(position2),
+        assertEquals(mCountriesAdapter.getItemId(position1), mListView.pointToRowId(0, 0));
+        assertEquals(mCountriesAdapter.getItemId(position2),
                 mListView.pointToRowId(50, middleOfSecondRow));
 
         assertTrue(position2 > position1);
     }
 
-    public void testDraw() {
-        Canvas canvas = new Canvas();
-        mListView.draw(canvas);
-
-        MyListView listView = new MyListView(mActivity);
-        listView.dispatchDraw(canvas);
-
-        // TODO: how to check
-    }
-
-    public void testSetRecyclerListener() throws Throwable {
+    @Test
+    public void testSetRecyclerListener() {
         setAdapter();
 
-        MockRecyclerListener recyclerListener = new MockRecyclerListener();
-        List<View> views = new ArrayList<View>();
+        AbsListView.RecyclerListener mockRecyclerListener =
+                mock(AbsListView.RecyclerListener.class);
+        verifyZeroInteractions(mockRecyclerListener);
 
-        assertNull(recyclerListener.getView());
-        mListView.setRecyclerListener(recyclerListener);
+        mListView.setRecyclerListener(mockRecyclerListener);
+        List<View> views = new ArrayList<>();
         mListView.reclaimViews(views);
 
         assertTrue(views.size() > 0);
-        assertNotNull(recyclerListener.getView());
 
-        assertSame(recyclerListener.getView(), views.get(views.size() - 1));
+        // Verify that onMovedToScrapHeap was called on each view in the order that they were
+        // put in the list that we passed to reclaimViews
+        final InOrder reclaimedOrder = inOrder(mockRecyclerListener);
+        for (View reclaimed : views) {
+            reclaimedOrder.verify(mockRecyclerListener, times(1)).onMovedToScrapHeap(reclaimed);
+        }
+        verifyNoMoreInteractions(mockRecyclerListener);
     }
 
+    @Test
     public void testAccessCacheColorHint() {
         mListView.setCacheColorHint(Color.RED);
         assertEquals(Color.RED, mListView.getCacheColorHint());
@@ -455,6 +488,7 @@
         assertEquals(Color.GRAY, mListView.getSolidColor());
     }
 
+    @Test
     public void testAccessTranscriptMode() {
         mListView.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
         assertEquals(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL, mListView.getTranscriptMode());
@@ -466,8 +500,9 @@
         assertEquals(AbsListView.TRANSCRIPT_MODE_NORMAL, mListView.getTranscriptMode());
     }
 
+    @Test
     public void testCheckLayoutParams() {
-        MyListView listView = new MyListView(mActivity);
+        MyListView listView = new MyListView(mContext);
 
         AbsListView.LayoutParams param1 = new AbsListView.LayoutParams(10, 10);
         assertTrue(listView.checkLayoutParams(param1));
@@ -476,15 +511,16 @@
         assertFalse(listView.checkLayoutParams(param2));
     }
 
+    @Test
     public void testComputeVerticalScrollValues() {
-        MyListView listView = new MyListView(mActivity);
+        MyListView listView = new MyListView(mContext);
         assertEquals(0, listView.computeVerticalScrollRange());
         assertEquals(0, listView.computeVerticalScrollOffset());
         assertEquals(0, listView.computeVerticalScrollExtent());
 
-        listView.setAdapter(mAdapter_countries);
+        listView.setAdapter(mCountriesAdapter);
         listView.setSmoothScrollbarEnabled(false);
-        assertEquals(mAdapter_countries.getCount(), listView.computeVerticalScrollRange());
+        assertEquals(mCountriesAdapter.getCount(), listView.computeVerticalScrollRange());
         assertEquals(0, listView.computeVerticalScrollOffset());
         assertEquals(0, listView.computeVerticalScrollExtent());
 
@@ -493,14 +529,15 @@
         assertEquals(0, listView.computeVerticalScrollExtent());
     }
 
+    @Test
     public void testGenerateLayoutParams() throws XmlPullParserException, IOException {
         ViewGroup.LayoutParams res = mListView.generateLayoutParams(mAttributeSet);
         assertNotNull(res);
         assertTrue(res instanceof AbsListView.LayoutParams);
 
-        MyListView listView = new MyListView(mActivity);
-        ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                                              ViewGroup.LayoutParams.WRAP_CONTENT);
+        MyListView listView = new MyListView(mContext);
+        ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
 
         res = listView.generateLayoutParams(p);
         assertNotNull(res);
@@ -509,6 +546,7 @@
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, res.height);
     }
 
+    @Test
     public void testBeforeAndAfterTextChanged() {
         // The java doc says these two methods do nothing
         CharSequence str = "test";
@@ -518,8 +556,8 @@
         mListView.afterTextChanged(sb);
 
         // test callback
-        MyListView listView = new MyListView(mActivity);
-        TextView tv = new TextView(mActivity);
+        MyListView listView = new MyListView(mContext);
+        TextView tv = new TextView(mContext);
 
         assertFalse(listView.isBeforeTextChangedCalled());
         assertFalse(listView.isOnTextChangedCalled());
@@ -536,8 +574,9 @@
         assertTrue(listView.isAfterTextChangedCalled());
     }
 
-    public void testAddTouchables() throws Throwable {
-        ArrayList<View> views = new ArrayList<View>();
+    @Test
+    public void testAddTouchables() {
+        ArrayList<View> views = new ArrayList<>();
         assertEquals(0, views.size());
 
         setAdapter();
@@ -546,78 +585,88 @@
         assertEquals(mListView.getChildCount(), views.size());
     }
 
-    public void testInvalidateViews() throws Throwable {
-        TextView tv1 = (TextView) mActivity.findViewById(R.id.headerview1);
-        TextView tv2 = (TextView) mActivity.findViewById(R.id.footerview1);
+    @Test
+    public void testInvalidateViews() {
+        final Activity activity = mActivityRule.getActivity();
+        TextView tv1 = (TextView) activity.findViewById(R.id.headerview1);
+        TextView tv2 = (TextView) activity.findViewById(R.id.footerview1);
 
         setAdapter();
 
         mListView.setScrollIndicators(tv1, tv2);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.invalidateViews();
-            }
-        });
+        mInstrumentation.runOnMainSync(mListView::invalidateViews);
         mInstrumentation.waitForIdleSync();
     }
 
-    public void testGetContextMenuInfo() throws Throwable {
-        final MyListView listView = new MyListView(mActivity, mAttributeSet);
+    @Test
+    public void testGetContextMenuInfo() {
+        final MyListView listView = new MyListView(mContext, mAttributeSet);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(listView);
-                listView.setAdapter(mAdapter_countries);
-                listView.setSelection(2);
-            }
+        mInstrumentation.runOnMainSync(() ->  {
+            mActivityRule.getActivity().setContentView(listView);
+            listView.setAdapter(mCountriesAdapter);
+            listView.setSelection(2);
         });
         mInstrumentation.waitForIdleSync();
 
         final TextView v = (TextView) listView.getSelectedView();
         assertNull(listView.getContextMenuInfo());
 
-        final MockOnItemLongClickListener listener = new MockOnItemLongClickListener();
-        listView.setOnItemLongClickListener(listener);
+        final AbsListView.OnItemLongClickListener mockOnItemLongClickListener =
+                mock(AbsListView.OnItemLongClickListener.class);
+        listView.setOnItemLongClickListener(mockOnItemLongClickListener);
 
-        assertNull(listener.getParent());
-        assertNull(listener.getView());
-        assertEquals(0, listener.getPosition());
-        assertEquals(0, listener.getID());
+        verifyZeroInteractions(mockOnItemLongClickListener);
+
+        // Create a count down latch and configure it to be counted down when our mock
+        // listener is invoked with the expected view
+        final CountDownLatch countDownLatch = new CountDownLatch(1);
+        doAnswer(new Answer<Void>() {
+             @Override
+             public Void answer(InvocationOnMock invocation) {
+                 countDownLatch.countDown();
+                 return null;
+             }
+         }).when(mockOnItemLongClickListener).onItemLongClick(listView, v, 2,
+                listView.getItemIdAtPosition(2));
 
         mInstrumentation.waitForIdleSync();
-        TouchUtils.longClickView(this, v);
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return v == listener.getView();
-            }
-        }.run();
+        // Now long click our view
+        CtsTouchUtils.emulateLongClick(mInstrumentation, v, 500);
 
-        assertSame(listView, listener.getParent());
-        assertEquals(2, listener.getPosition());
-        assertEquals(listView.getItemIdAtPosition(2), listener.getID());
+        // And wait for the latch to be triggered
+        try {
+            assertTrue(countDownLatch.await(20L, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+        }
+
+        verify(mockOnItemLongClickListener, times(1)).onItemLongClick(listView, v, 2,
+                listView.getItemIdAtPosition(2));
 
         ContextMenuInfo cmi = listView.getContextMenuInfo();
         assertNotNull(cmi);
     }
 
+    @Test
     public void testGetTopBottomFadingEdgeStrength() {
-        MyListView listView = new MyListView(mActivity);
+        MyListView listView = new MyListView(mContext);
 
         assertEquals(0.0f, listView.getTopFadingEdgeStrength(), DELTA);
         assertEquals(0.0f, listView.getBottomFadingEdgeStrength(), DELTA);
     }
 
+    @Test
     public void testHandleDataChanged() {
-        MyListView listView = new MyListView(mActivity, mAttributeSet, 0);
+        MyListView listView = new MyListView(mContext, mAttributeSet, 0);
         listView.handleDataChanged();
         // TODO: how to check?
     }
 
+    @Test
     public void testSetFilterText() {
-        MyListView listView = new MyListView(mActivity, mAttributeSet, 0);
+        MyListView listView = new MyListView(mContext, mAttributeSet, 0);
         String filterText = "xyz";
 
         assertFalse(listView.isTextFilterEnabled());
@@ -650,231 +699,420 @@
     }
 
     @MediumTest
-    public void testSetItemChecked_multipleModeSameValue()
-            throws Throwable {
+    @Test
+    public void testSetItemChecked_multipleModeSameValue() {
         // Calling setItemChecked with the same value in multiple choice mode should not cause
         // requestLayout
         mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, false);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(0, false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mListView.isLayoutRequested());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, false);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(0, false));
         assertFalse(mListView.isLayoutRequested());
     }
 
     @MediumTest
-    public void testSetItemChecked_singleModeSameValue()
-            throws Throwable {
+    @Test
+    public void testSetItemChecked_singleModeSameValue() {
         // Calling setItemChecked with the same value in single choice mode should not cause
         // requestLayout
         mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, false);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(0, false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mListView.isLayoutRequested());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, false);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(0, false));
         assertFalse(mListView.isLayoutRequested());
     }
 
     @MediumTest
-    public void testSetItemChecked_multipleModeDifferentValue()
-            throws Throwable {
+    @Test
+    public void testSetItemChecked_multipleModeDifferentValue() {
         // Calling setItemChecked with a different value in multiple choice mode should cause
         // requestLayout
         mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, false);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(0, false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mListView.isLayoutRequested());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, true);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(0, true));
         assertTrue(mListView.isLayoutRequested());
     }
 
     @MediumTest
-    public void testSetItemChecked_singleModeDifferentValue()
-            throws Throwable {
+    @Test
+    public void testSetItemChecked_singleModeDifferentValue() {
         // Calling setItemChecked with a different value in single choice mode should cause
         // requestLayout
         mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, false);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(0, false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mListView.isLayoutRequested());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, true);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(0, true));
         assertTrue(mListView.isLayoutRequested());
     }
 
-    public void testLayoutChildren() {
-        /**
-         * the subclass ListView and GridView override this method, so we can not test
-         * this method.
-         */
+    @LargeTest
+    @Test
+    public void testTextFilter() {
+        setAdapter();
+
+        // Default state - no text filter
+        assertFalse(mListView.isTextFilterEnabled());
+        assertFalse(mListView.hasTextFilter());
+        assertTrue(TextUtils.isEmpty(mListView.getTextFilter()));
+
+        // Enable text filter and verify that while it's enabled, the filtering is
+        // still no on
+        mInstrumentation.runOnMainSync(() -> mListView.setTextFilterEnabled(true));
+        assertTrue(mListView.isTextFilterEnabled());
+        assertFalse(mListView.hasTextFilter());
+        assertTrue(TextUtils.isEmpty(mListView.getTextFilter()));
+
+        // Verify the initial content of the list
+        assertEquals(COUNTRY_LIST.length, mListView.getCount());
+
+        // Set text filter to A - we expect four entries to be left displayed in the list
+        mInstrumentation.runOnMainSync(() -> mListView.setFilterText("A"));
+        PollingCheck.waitFor(() -> mListView.getCount() == 4);
+        assertTrue(mListView.isTextFilterEnabled());
+        assertTrue(mListView.hasTextFilter());
+        assertTrue(TextUtils.equals("A", mListView.getTextFilter()));
+
+        // Set text filter to Ar - we expect three entries to be left displayed in the list
+        mInstrumentation.runOnMainSync(() -> mListView.setFilterText("Ar"));
+        PollingCheck.waitFor(() -> mListView.getCount() == 3);
+        assertTrue(mListView.isTextFilterEnabled());
+        assertTrue(mListView.hasTextFilter());
+        assertTrue(TextUtils.equals("Ar", mListView.getTextFilter()));
+
+        // Clear text filter - we expect to go back to the initial content
+        mInstrumentation.runOnMainSync(() -> mListView.clearTextFilter());
+        PollingCheck.waitFor(() -> mListView.getCount() == COUNTRY_LIST.length);
+        assertTrue(mListView.isTextFilterEnabled());
+        assertFalse(mListView.hasTextFilter());
+        assertTrue(TextUtils.isEmpty(mListView.getTextFilter()));
+
+        // Set text filter to Be - we expect four entries to be left displayed in the list
+        mInstrumentation.runOnMainSync(() -> mListView.setFilterText("Be"));
+        PollingCheck.waitFor(() -> mListView.getCount() == 4);
+        assertTrue(mListView.isTextFilterEnabled());
+        assertTrue(mListView.hasTextFilter());
+        assertTrue(TextUtils.equals("Be", mListView.getTextFilter()));
+
+        // Set text filter to Q - we no entries displayed in the list
+        mInstrumentation.runOnMainSync(() -> mListView.setFilterText("Q"));
+        PollingCheck.waitFor(() -> mListView.getCount() == 0);
+        assertTrue(mListView.isTextFilterEnabled());
+        assertTrue(mListView.hasTextFilter());
+        assertTrue(TextUtils.equals("Q", mListView.getTextFilter()));
     }
 
-    public void testFoo() {
-        /**
-         * Do not test these APIs. They are callbacks which:
-         *
-         * 1. The callback machanism has been tested in super class
-         * 2. The functionality is implmentation details, no need to test
-         */
+    @Test
+    public void testOnFilterComplete() {
+        // Note that we're not using spy() due to Mockito not being able to spy on ListView,
+        // at least yet.
+        final MyListView listView = new MyListView(mContext, mAttributeSet);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mActivityRule.getActivity().setContentView(listView);
+            listView.setAdapter(mCountriesAdapter);
+            listView.setTextFilterEnabled(true);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Set text filter to A - we expect four entries to be left displayed in the list
+        mInstrumentation.runOnMainSync(() -> listView.setFilterText("A"));
+        PollingCheck.waitFor(() -> listView.getCount() == 4);
+        assertTrue(listView.isTextFilterEnabled());
+        assertTrue(listView.hasTextFilter());
+        assertTrue(TextUtils.equals("A", listView.getTextFilter()));
+
+        assertEquals(4, listView.getOnFilterCompleteCount());
     }
 
-    private static class MockOnScrollListener implements OnScrollListener {
-        private AbsListView mView;
-        private int mFirstVisibleItem;
-        private int mVisibleItemCount;
-        private int mTotalItemCount;
-        private int mScrollState;
-
-        private boolean mIsOnScrollCalled;
-        private boolean mIsOnScrollStateChangedCalled;
-
-        private MockOnScrollListener() {
-            mView = null;
-            mFirstVisibleItem = 0;
-            mVisibleItemCount = 0;
-            mTotalItemCount = 0;
-            mScrollState = -1;
-
-            mIsOnScrollCalled = false;
-            mIsOnScrollStateChangedCalled = false;
+    private static class PositionArrayAdapter<T> extends ArrayAdapter<T> {
+        public PositionArrayAdapter(Context context, int resource, List<T> objects) {
+            super(context, resource, objects);
         }
 
-        public void onScroll(AbsListView view, int firstVisibleItem,
-                int visibleItemCount, int totalItemCount) {
-            mView = view;
-            mFirstVisibleItem = firstVisibleItem;
-            mVisibleItemCount = visibleItemCount;
-            mTotalItemCount = totalItemCount;
-            mIsOnScrollCalled = true;
-        }
-
-        public void onScrollStateChanged(AbsListView view, int scrollState) {
-            mScrollState = scrollState;
-            mIsOnScrollStateChangedCalled = true;
-        }
-
-        public AbsListView getView() {
-            return mView;
-        }
-
-        public int getFirstVisibleItem() {
-            return mFirstVisibleItem;
-        }
-
-        public int getVisibleItemCount() {
-            return mVisibleItemCount;
-        }
-
-        public int getTotalItemCount() {
-            return mTotalItemCount;
-        }
-
-        public int getScrollState() {
-            return mScrollState;
-        }
-
-        public boolean isOnScrollCalled() {
-            return mIsOnScrollCalled;
-        }
-
-        public boolean isOnScrollStateChangedCalled() {
-            return mIsOnScrollStateChangedCalled;
-        }
-
-        public void reset() {
-            mIsOnScrollCalled = false;
-            mIsOnScrollStateChangedCalled = false;
-        }
-    }
-
-    private static class MockRecyclerListener implements RecyclerListener {
-        private View mView;
-
-        private MockRecyclerListener() {
-            mView = null;
-        }
-
-        public void onMovedToScrapHeap(View view) {
-            mView = view;
-        }
-
-        public View getView() {
-            return mView;
-        }
-    }
-
-    private static class MockOnItemLongClickListener implements OnItemLongClickListener {
-        private AdapterView<?> parent;
-        private View view;
-        private int position;
-        private long id;
-
-        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
-            this.parent = parent;
-            this.view = view;
-            this.position = position;
-            this.id = id;
-            return false;
-        }
-
-        public AdapterView<?> getParent() {
-            return parent;
-        }
-
-        public View getView() {
-            return view;
-        }
-
-        public int getPosition() {
+        @Override
+        public long getItemId(int position) {
             return position;
         }
 
-        public long getID() {
-            return id;
+        @Override
+        public boolean hasStableIds() {
+            return true;
         }
     }
 
+    private void verifyCheckedState(final long[] expectedCheckedItems) {
+        TestUtils.assertIdentical(expectedCheckedItems, mListView.getCheckedItemIds());
+
+        assertEquals(expectedCheckedItems.length, mListView.getCheckedItemCount());
+
+        final long expectedCheckedItemPosition =
+                (mListView.getChoiceMode() == AbsListView.CHOICE_MODE_SINGLE) &&
+                        (expectedCheckedItems.length == 1)
+                        ? expectedCheckedItems[0]
+                        : AbsListView.INVALID_POSITION;
+        assertEquals(expectedCheckedItemPosition, mListView.getCheckedItemPosition());
+
+        // Note that getCheckedItemPositions doesn't have a guarantee that it only holds
+        // true values, which is why we're not doing the size() == 0 check even in the initial
+        // state
+        TestUtils.assertTrueValuesAtPositions(
+                expectedCheckedItems, mListView.getCheckedItemPositions());
+    }
+
+    @MediumTest
+    @Test
+    public void testCheckedItemsUnderNoneChoiceMode() {
+        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);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                () -> mListView.setAdapter(adapter));
+
+        mInstrumentation.runOnMainSync(
+                () -> mListView.setChoiceMode(AbsListView.CHOICE_MODE_NONE));
+        verifyCheckedState(new long[] {});
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, true));
+        verifyCheckedState(new long[] {});
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, true));
+        verifyCheckedState(new long[] {});
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, false));
+        verifyCheckedState(new long[] {});
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, false));
+        verifyCheckedState(new long[] {});
+    }
+
+    @MediumTest
+    @Test
+    public void testCheckedItemsUnderSingleChoiceMode() {
+        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);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                () -> mListView.setAdapter(adapter));
+
+        mInstrumentation.runOnMainSync(
+                () -> mListView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE));
+        verifyCheckedState(new long[] {});
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, true));
+        verifyCheckedState(new long[] { 2 });
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, true));
+        verifyCheckedState(new long[] { 4 });
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, false));
+        verifyCheckedState(new long[] { 4 });
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, false));
+        verifyCheckedState(new long[] {});
+    }
+
+    @MediumTest
+    @Test
+    public void testCheckedItemsUnderMultipleChoiceMode() {
+        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);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                () -> mListView.setAdapter(adapter));
+
+        mInstrumentation.runOnMainSync(
+                () -> mListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE));
+        verifyCheckedState(new long[] {});
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, true));
+        verifyCheckedState(new long[] { 2 });
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, true));
+        verifyCheckedState(new long[] { 2, 4 });
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, false));
+        verifyCheckedState(new long[] { 4 });
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, false));
+        verifyCheckedState(new long[] {});
+    }
+
+    private void configureMultiChoiceModalState() {
+        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);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                () -> mListView.setAdapter(adapter));
+
+        // Configure a multi-choice mode listener to configure our test contextual action bar
+        // content. We will subsequently query that listener for calls to its
+        // onItemCheckedStateChanged method
+        mMultiChoiceModeListener =
+                mock(AbsListView.MultiChoiceModeListener.class);
+        doAnswer((InvocationOnMock invocation) -> {
+            final ActionMode actionMode = (ActionMode) invocation.getArguments() [0];
+            final Menu menu = (Menu) invocation.getArguments() [1];
+            actionMode.getMenuInflater().inflate(R.menu.cab_menu, menu);
+            return true;
+        }).when(mMultiChoiceModeListener).onCreateActionMode(
+                any(ActionMode.class), any(Menu.class));
+        mListView.setMultiChoiceModeListener(mMultiChoiceModeListener);
+
+        mInstrumentation.runOnMainSync(
+                () -> mListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL));
+        verifyCheckedState(new long[] {});
+    }
+
+    @MediumTest
+    @Test
+    public void testCheckedItemsUnderMultipleModalChoiceMode() {
+        configureMultiChoiceModalState();
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, true));
+        verifyCheckedState(new long[] { 2 });
+        verify(mMultiChoiceModeListener, times(1)).onItemCheckedStateChanged(
+                any(ActionMode.class), eq(2), eq(2L), eq(true));
+
+        reset(mMultiChoiceModeListener);
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, true));
+        verifyCheckedState(new long[] { 2, 4 });
+        verify(mMultiChoiceModeListener, times(1)).onItemCheckedStateChanged(
+                any(ActionMode.class), eq(4), eq(4L), eq(true));
+
+        reset(mMultiChoiceModeListener);
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, false));
+        verifyCheckedState(new long[] { 4 });
+        verify(mMultiChoiceModeListener, times(1)).onItemCheckedStateChanged(
+                any(ActionMode.class), eq(2), eq(2L), eq(false));
+
+        reset(mMultiChoiceModeListener);
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, false));
+        verifyCheckedState(new long[] {});
+        mListView.setMultiChoiceModeListener(mMultiChoiceModeListener);
+        verify(mMultiChoiceModeListener, times(1)).onItemCheckedStateChanged(
+                any(ActionMode.class), eq(4), eq(4L), eq(false));
+    }
+
+    private void configureMultiChoiceModeListenerOnItemChecked(final CountDownLatch countDownLatch,
+            int positionToBecomeChecked) {
+        doAnswer((InvocationOnMock invocation) -> {
+            countDownLatch.countDown();
+            return null;
+        }).when(mMultiChoiceModeListener).onItemCheckedStateChanged(
+                any(ActionMode.class), eq(positionToBecomeChecked),
+                eq((long) positionToBecomeChecked), eq(true));
+    }
+
+    @LargeTest
+    @Test
+    public void testMultiSelectionWithLongPressAndTaps() {
+        configureMultiChoiceModalState();
+
+        final int firstVisiblePosition = mListView.getFirstVisiblePosition();
+        final int lastVisiblePosition = mListView.getLastVisiblePosition();
+
+        // Emulate long-click on the middle item of the currently visible content
+        final int positionForInitialSelection = (firstVisiblePosition + lastVisiblePosition) / 2;
+        final CountDownLatch initialCheckedLatch = new CountDownLatch(1);
+        configureMultiChoiceModeListenerOnItemChecked(
+                initialCheckedLatch, positionForInitialSelection);
+        CtsTouchUtils.emulateLongClick(mInstrumentation,
+                mListView.getChildAt(positionForInitialSelection));
+        try {
+            assertTrue(initialCheckedLatch.await(1, TimeUnit.SECONDS));
+        } catch (InterruptedException ie) {
+            fail();
+        }
+        // and verify that the item is now checked
+        verifyCheckedState(new long[] { positionForInitialSelection });
+
+        if (firstVisiblePosition != positionForInitialSelection) {
+            final CountDownLatch secondCheckedLatch = new CountDownLatch(1);
+            configureMultiChoiceModeListenerOnItemChecked(
+                    secondCheckedLatch, firstVisiblePosition);
+            // Tap the first element in our list
+            CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation,
+                    mListView.getChildAt(firstVisiblePosition));
+            try {
+                assertTrue(secondCheckedLatch.await(1, TimeUnit.SECONDS));
+            } catch (InterruptedException ie) {
+                fail();
+            }
+            // and verify that the item is now checked
+            verifyCheckedState(new long[] { firstVisiblePosition, positionForInitialSelection });
+        }
+
+        // Scroll down
+        CtsTouchUtils.emulateScrollToBottom(mInstrumentation, mListView);
+        final int lastListPosition = COUNTRY_LIST.length - 1;
+        if (lastListPosition != positionForInitialSelection) {
+            final CountDownLatch thirdCheckedLatch = new CountDownLatch(1);
+            configureMultiChoiceModeListenerOnItemChecked(thirdCheckedLatch, lastListPosition);
+            // Tap the last element in our list
+            CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation,
+                    mListView.getChildAt(mListView.getChildCount() - 1));
+            try {
+                assertTrue(thirdCheckedLatch.await(1, TimeUnit.SECONDS));
+            } catch (InterruptedException ie) {
+                fail();
+            }
+            // and verify that the item is now checked and our listener has been notified
+            verifyCheckedState(new long[] { firstVisiblePosition, positionForInitialSelection,
+                    lastListPosition });
+        }
+    }
+
+    @LargeTest
+    @Test
+    public void testFastScroll() {
+        setAdapter();
+
+        final int lastVisiblePosition = mListView.getLastVisiblePosition();
+        if (lastVisiblePosition == (COUNTRY_LIST.length - 1)) {
+            // This can happen on very large screens - the entire content fits and there's
+            // nothing to scroll
+            return;
+        }
+
+        mListView.setFastScrollAlwaysVisible(true);
+        assertTrue(mListView.isFastScrollEnabled());
+        assertTrue(mListView.isFastScrollAlwaysVisible());
+
+        final int[] listViewOnScreenXY = new int[2];
+        mListView.getLocationOnScreen(listViewOnScreenXY);
+
+        final int topEdgeY = listViewOnScreenXY[1];
+        final int bottomEdgeY = listViewOnScreenXY[1] + mListView.getHeight();
+        final int rightEdgeX = listViewOnScreenXY[0] + mListView.getWidth();
+
+        // Emulate a downwards gesture that should bring us all the way to the last element
+        // of the list (when fast scroll is enabled)
+        CtsTouchUtils.emulateDragGesture(mInstrumentation,
+                rightEdgeX - 1,              // X start of the drag
+                topEdgeY + 1,                // Y start of the drag
+                0,                           // X amount of the drag (vertical)
+                mListView.getHeight() - 2);  // Y amount of the drag (downwards)
+
+        assertEquals(COUNTRY_LIST.length - 1, mListView.getLastVisiblePosition());
+
+        // Emulate an upwards gesture that should bring us all the way to the first element
+        // of the list (when fast scroll is enabled)
+        CtsTouchUtils.emulateDragGesture(mInstrumentation,
+                rightEdgeX - 1,               // X start of the drag
+                bottomEdgeY - 1,              // Y start of the drag
+                0,                            // X amount of the drag (vertical)
+                -mListView.getHeight() + 2);  // Y amount of the drag (upwards)
+
+        assertEquals(0, mListView.getFirstVisiblePosition());
+    }
+
     /**
-     * MyListView for test
+     * MyListView for test.
      */
     private static class MyListView extends ListView {
         public MyListView(Context context) {
@@ -982,5 +1220,17 @@
         public boolean isAfterTextChangedCalled() {
             return mIsAfterTextChangedCalled;
         }
+
+        private int mOnFilterCompleteCount = -1;
+
+        @Override
+        public void onFilterComplete(int count) {
+            super.onFilterComplete(count);
+            mOnFilterCompleteCount = count;
+        }
+
+        public int getOnFilterCompleteCount() {
+            return mOnFilterCompleteCount;
+        }
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListView_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/AbsListView_LayoutParamsTest.java
index 7e88a19..ca73a2f 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListView_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListView_LayoutParamsTest.java
@@ -16,37 +16,45 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.junit.Assert.assertEquals;
 
-
-import org.xmlpull.v1.XmlPullParser;
-
+import android.content.Context;
 import android.cts.util.WidgetTestUtils;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.widget.AbsListView;
 import android.widget.AbsListView.LayoutParams;
 
-public class AbsListView_LayoutParamsTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AbsListView_LayoutParamsTest {
+    private Context mContext;
     private AttributeSet mAttributeSet;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
+    @Before
+    public void setup() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
         XmlPullParser parser = mContext.getResources().getXml(R.layout.abslistview_layout);
         WidgetTestUtils.beginDocument(parser, "ViewGroup_Layout");
         mAttributeSet = Xml.asAttributeSet(parser);
     }
 
+    @Test
     public void testConstructors() {
         int TEST_WIDTH = 25;
         int TEST_HEIGHT = 25;
         int TEST_HEIGHT2 = 30;
         AbsListView.LayoutParams layoutParams;
 
-        layoutParams = new AbsListView.LayoutParams(getContext(), mAttributeSet);
+        layoutParams = new AbsListView.LayoutParams(mContext, mAttributeSet);
         assertEquals(TEST_WIDTH, layoutParams.width);
         assertEquals(TEST_HEIGHT, layoutParams.height);
 
diff --git a/tests/tests/widget/src/android/widget/cts/AbsListView_ScrollTest.java b/tests/tests/widget/src/android/widget/cts/AbsListView_ScrollTest.java
new file mode 100644
index 0000000..e3246d3
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/AbsListView_ScrollTest.java
@@ -0,0 +1,729 @@
+/*
+ * 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.widget.cts;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.cts.util.CtsTouchUtils;
+import android.cts.util.PollingCheck;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.*;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class AbsListView_ScrollTest {
+    private static final int ROW_HEIGHT_PX = 40;
+    private static final String[] COUNTRY_LIST = new String[] {
+            "Argentina", "Armenia", "Aruba", "Australia", "Belarus", "Belgium", "Belize", "Benin",
+            "Botswana", "Brazil", "Cameroon", "China", "Colombia", "Costa Rica", "Cyprus",
+            "Denmark", "Djibouti", "Ethiopia", "Fiji", "Finland", "France", "Gabon", "Germany",
+            "Ghana", "Haiti", "Honduras", "Iceland", "India", "Indonesia", "Ireland", "Italy",
+            "Japan", "Kiribati", "Laos", "Lesotho", "Liberia", "Malaysia", "Mongolia", "Myanmar",
+            "Nauru", "Norway", "Oman", "Pakistan", "Philippines", "Portugal", "Romania", "Russia",
+            "Rwanda", "Singapore", "Slovakia", "Slovenia", "Somalia", "Swaziland", "Togo", "Tuvalu",
+            "Uganda", "Ukraine", "United States", "Vanuatu", "Venezuela", "Zimbabwe"
+    };
+
+    @Rule
+    public ActivityTestRule<ListViewFixedCtsActivity> mActivityRule
+            = new ActivityTestRule<>(ListViewFixedCtsActivity.class);
+
+    private AbsListView mListView;
+    private Context mContext;
+    private Instrumentation mInstrumentation;
+    private ArrayAdapter<String> mCountriesAdapter;
+
+    @Before
+    public void setup() throws Exception {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
+
+        final Activity activity = mActivityRule.getActivity();
+
+        PollingCheck.waitFor(() -> activity.hasWindowFocus());
+
+        mCountriesAdapter = new ArrayAdapter<>(mContext,
+                R.layout.listitemfixed_layout, COUNTRY_LIST);
+
+        mListView = (ListView) activity.findViewById(R.id.listview_default);
+        mInstrumentation.runOnMainSync(() -> mListView.setAdapter(mCountriesAdapter));
+        mInstrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Listener that allows waiting for the end of a scroll. When the tracked
+     * {@link AbsListView} transitions to idle state, the passed {@link CountDownLatch}
+     * is notified.
+     */
+    private class ScrollIdleListListener implements OnScrollListener {
+        private CountDownLatch mLatchToNotify;
+
+        public ScrollIdleListListener(CountDownLatch latchToNotify) {
+            mLatchToNotify = latchToNotify;
+        }
+
+        @Override
+        public void onScrollStateChanged(AbsListView view, int scrollState) {
+            if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
+                mListView.setOnScrollListener(null);
+                mLatchToNotify.countDown();
+            }
+        }
+
+        @Override
+        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+                int totalItemCount) {
+        }
+    }
+
+    /**
+     * Listener that allows waiting until a specific position in the list becomes visible.
+     * When the tracked position in the {@link AbsListView} becomes visible, the passed
+     * {@link CountDownLatch} is notified.
+     */
+    private class ScrollPositionListListener implements AbsListView.OnScrollListener {
+        private CountDownLatch mLatchToNotify;
+        private int mTargetPosition;
+
+        public ScrollPositionListListener(CountDownLatch latchToNotify, int targetPosition) {
+            mLatchToNotify = latchToNotify;
+            mTargetPosition = targetPosition;
+        }
+
+        @Override
+        public void onScrollStateChanged(AbsListView view, int scrollState) {
+        }
+
+        @Override
+        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+                int totalItemCount) {
+            // Is our target in current visible range?
+            int lastVisibleItem = firstVisibleItem + visibleItemCount - 1;
+            boolean isInRange = (mTargetPosition >= firstVisibleItem) &&
+                    (mTargetPosition <= lastVisibleItem);
+            if (!isInRange) {
+                return;
+            }
+
+            // Is our target also fully visible?
+            int visibleIndexOfTarget = mTargetPosition - firstVisibleItem;
+            View targetChild = mListView.getChildAt(visibleIndexOfTarget);
+            boolean isTargetFullyVisible = (targetChild.getTop() >= 0) &&
+                    (targetChild.getBottom() <= mListView.getHeight());
+            if (isTargetFullyVisible) {
+                mListView.setOnScrollListener(null);
+                mLatchToNotify.countDown();
+            }
+        }
+    }
+
+    private boolean isItemVisible(int position) {
+        return (position >= mListView.getFirstVisiblePosition()) &&
+                (position <= mListView.getLastVisiblePosition());
+    }
+
+    private void verifyScrollToPosition(int positionToScrollTo) {
+        final int firstVisiblePosition = mListView.getFirstVisiblePosition();
+        final int lastVisiblePosition = mListView.getLastVisiblePosition();
+
+        if ((positionToScrollTo >= firstVisiblePosition) &&
+                (positionToScrollTo <= lastVisiblePosition)) {
+            // If it's already on the screen, we won't have any real scrolling taking
+            // place, so our tracking based on scroll state change will time out. This
+            // is why we're returning here early.
+            return;
+        }
+
+        // Register a scroll listener on our ListView. The listener will notify our latch
+        // when the scroll state changes to IDLE. If that never happens, the latch will
+        // time out and fail the test.
+        final CountDownLatch latch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(latch));
+        mInstrumentation.runOnMainSync(() -> mListView.smoothScrollToPosition(
+                positionToScrollTo));
+
+        boolean result = false;
+        try {
+            result = latch.await(2, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Timed out while waiting for the scroll to complete", result);
+
+        // Verify that the position we've been asked to scroll to is visible
+        assertTrue("Asked to scroll to " + positionToScrollTo + ", first visible is "
+                + mListView.getFirstVisiblePosition() + ", last visible is "
+                + mListView.getLastVisiblePosition(), isItemVisible(positionToScrollTo));
+    }
+
+    @Test
+    public void testSmoothScrollToPositionDownUpDown() {
+        final int itemCount = COUNTRY_LIST.length;
+
+        // Scroll closer to the end of the list
+        verifyScrollToPosition(itemCount - 10);
+        // Scroll back towards the beginning of the list
+        verifyScrollToPosition(5);
+        // And then towards the end of the list again
+        verifyScrollToPosition(itemCount - 1);
+        // And back up to the middle of the list
+        verifyScrollToPosition(itemCount / 2);
+    }
+
+    @Test
+    public void testSmoothScrollToPositionEveryRow() {
+        final int itemCount = COUNTRY_LIST.length;
+
+        for (int i = 0; i < itemCount; i++) {
+            // Scroll one row down
+            verifyScrollToPosition(i);
+        }
+
+        for (int i = itemCount - 1; i >= 0; i--) {
+            // Scroll one row up
+            verifyScrollToPosition(i);
+        }
+    }
+
+    private void verifyScrollToPositionWithBound(int positionToScrollTo, int boundPosition,
+            boolean expectTargetPositionToBeVisibleAtEnd) {
+        final int firstVisiblePosition = mListView.getFirstVisiblePosition();
+        final int lastVisiblePosition = mListView.getLastVisiblePosition();
+
+        if ((positionToScrollTo >= firstVisiblePosition) &&
+                (positionToScrollTo <= lastVisiblePosition)) {
+            // If it's already on the screen, we won't have any real scrolling taking
+            // place, so our tracking based on scroll state change will time out. This
+            // is why we're returning here early.
+            return;
+        }
+
+        // Register a scroll listener on our ListView. The listener will notify our latch
+        // when the scroll state changes to IDLE. If that never happens, the latch will
+        // time out and fail the test.
+        final CountDownLatch latch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(latch));
+        mInstrumentation.runOnMainSync(() -> mListView.smoothScrollToPosition(
+                positionToScrollTo, boundPosition));
+
+        boolean result = false;
+        try {
+            result = latch.await(2, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Timed out while waiting for the scroll to complete", result);
+
+        // Verify that the bound position is visible
+        assertTrue("Asked to scroll to " + positionToScrollTo + " with bound " + boundPosition
+                + ", first visible is " + mListView.getFirstVisiblePosition()
+                + ", last visible is " + mListView.getLastVisiblePosition(),
+                isItemVisible(boundPosition));
+
+        assertEquals("Asked to scroll to " + positionToScrollTo + " with bound " + boundPosition
+                + ", first visible is " + mListView.getFirstVisiblePosition()
+                + ", last visible is " + mListView.getLastVisiblePosition(),
+                expectTargetPositionToBeVisibleAtEnd, isItemVisible(positionToScrollTo));
+    }
+
+    @Test
+    public void testSmoothScrollToPositionWithBound() {
+        // Our list is 300px high and each row is 40px high. Without being too precise,
+        // the logic in this method relies on at least 8 and at most 10 items on the screen
+        // at any time.
+
+        // Scroll to 20 with bound at 6. This should result in the scroll stopping before it
+        // gets to 20 so that 6 is still visible
+        verifyScrollToPositionWithBound(20, 6, false);
+
+        // Scroll to 40 with bound at 35. This should result in the scroll getting to 40 becoming
+        // visible with 35 visible as well
+        verifyScrollToPositionWithBound(40, 35, true);
+
+        // Scroll to 10 with bound at 25. This should result in the scroll stopping before it
+        // gets to 10 so that 25 is still visible
+        verifyScrollToPositionWithBound(10, 25, false);
+
+        // Scroll to 5 with bound at 8. This should result in the scroll getting to 5 becoming
+        // visible with 8 visible as well
+        verifyScrollToPositionWithBound(5, 8, true);
+    }
+
+    private void verifyScrollToPositionFromTop(int positionToScrollTo, int offset,
+            int durationMs) {
+        final int startTopPositionInListCoordinates =
+                mListView.getFirstVisiblePosition() * ROW_HEIGHT_PX -
+                        mListView.getChildAt(0).getTop();
+        int targetTopPositionInListCoordinates = positionToScrollTo * ROW_HEIGHT_PX - offset;
+        // Need to clamp it to account for requests that would scroll the content outside
+        // of the available bounds
+        targetTopPositionInListCoordinates = Math.max(0, targetTopPositionInListCoordinates);
+        targetTopPositionInListCoordinates = Math.min(
+                COUNTRY_LIST.length * ROW_HEIGHT_PX - mListView.getHeight(),
+                targetTopPositionInListCoordinates);
+
+        if (targetTopPositionInListCoordinates == startTopPositionInListCoordinates) {
+            // If it's already at the target state, we won't have any real scrolling taking
+            // place, so our tracking based on scroll state change will time out. This
+            // is why we're returning here early.
+            return;
+        }
+
+        // Register a scroll listener on our ListView. The listener will notify our latch
+        // when the scroll state changes to IDLE. If that never happens, the latch will
+        // time out and fail the test.
+        final CountDownLatch latch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(latch));
+        if (durationMs > 0) {
+            mInstrumentation.runOnMainSync(() -> mListView.smoothScrollToPositionFromTop(
+                    positionToScrollTo, offset, durationMs));
+        } else {
+            mInstrumentation.runOnMainSync(() -> mListView.smoothScrollToPositionFromTop(
+                    positionToScrollTo, offset));
+        }
+
+        boolean result = false;
+        try {
+            // Since position-based scroll is emulated as a series of mini-flings, scrolling
+            // might take considerable time.
+            int timeoutMs = durationMs > 0 ? 5000 + durationMs : 5000;
+            result = latch.await(timeoutMs, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Timed out while waiting for the scroll to complete", result);
+
+        final int endTopPositionInListCoordinates =
+                mListView.getFirstVisiblePosition() * ROW_HEIGHT_PX -
+                        mListView.getChildAt(0).getTop();
+
+        assertEquals(targetTopPositionInListCoordinates, endTopPositionInListCoordinates);
+    }
+
+    @Test
+    public void testSmoothScrollToPositionFromTop() {
+        // Ask to scroll so that the top of position 5 is 20 pixels below the top edge of the list
+        verifyScrollToPositionFromTop(5, 10, -1);
+
+        // Ask to scroll so that the top of position 10 is right at the top edge of the list
+        verifyScrollToPositionFromTop(10, 0, -1);
+
+        // Ask to scroll so that the top of position 5 is 80 pixels below the top edge of the list
+        // (which means that since row height is 40 pixels high, the top item should be 3
+        verifyScrollToPositionFromTop(5, 80, -1);
+
+        // Ask to scroll so that the top of position 20 is 20 pixels above the top edge of the list
+        verifyScrollToPositionFromTop(20, 20, -1);
+
+        // Ask to scroll so that the top of position 20 is right at the top edge of the list
+        verifyScrollToPositionFromTop(20, 0, -1);
+
+        // Ask to scroll so that the top of position 20 is 20 pixels below the top edge of the list
+        verifyScrollToPositionFromTop(20, 20, -1);
+
+        // Ask to scroll beyond the top of the content
+        verifyScrollToPositionFromTop(0, -20, -1);
+        verifyScrollToPositionFromTop(0, -60, -1);
+
+        // Ask to scroll beyond the bottom of the content
+        final int itemCount = COUNTRY_LIST.length;
+        verifyScrollToPositionFromTop(itemCount - 1, 0, -1);
+        verifyScrollToPositionFromTop(itemCount - 1, mListView.getHeight(), -1);
+    }
+
+    @Test
+    public void testSmoothScrollToPositionFromTopWithTime() {
+        // Ask to scroll so that the top of position 5 is 20 pixels below the top edge of the list
+        verifyScrollToPositionFromTop(5, 10, 200);
+
+        // Ask to scroll so that the top of position 10 is right at the top edge of the list
+        verifyScrollToPositionFromTop(10, 0, 1000);
+
+        // Ask to scroll so that the top of position 5 is 80 pixels below the top edge of the list
+        // (which means that since row height is 40 pixels high, the top item should be 3
+        verifyScrollToPositionFromTop(5, 80, 500);
+
+        // Ask to scroll so that the top of position 20 is 20 pixels above the top edge of the list
+        verifyScrollToPositionFromTop(20, 20, 100);
+
+        // Ask to scroll so that the top of position 20 is right at the top edge of the list
+        verifyScrollToPositionFromTop(20, 0, 700);
+
+        // Ask to scroll so that the top of position 20 is 20 pixels below the top edge of the list
+        verifyScrollToPositionFromTop(20, 20, 600);
+
+        // Ask to scroll beyond the top of the content
+        verifyScrollToPositionFromTop(0, -20, 2000);
+        verifyScrollToPositionFromTop(0, -60, 300);
+
+        // Ask to scroll beyond the bottom of the content
+        final int itemCount = COUNTRY_LIST.length;
+        verifyScrollToPositionFromTop(itemCount - 1, 0, 600);
+        verifyScrollToPositionFromTop(itemCount - 1, mListView.getHeight(), 200);
+    }
+
+    @Test
+    public void testCanScrollList() {
+        final int itemCount = COUNTRY_LIST.length;
+
+        assertEquals(0, mListView.getFirstVisiblePosition());
+
+        // Verify that when we're at the top of the list, we can't scroll up but we can scroll
+        // down.
+        assertFalse(mListView.canScrollList(-1));
+        assertTrue(mListView.canScrollList(1));
+
+        // Scroll down to the very end of the list
+        verifyScrollToPosition(itemCount - 1);
+        assertEquals(itemCount - 1, mListView.getLastVisiblePosition());
+
+        // Verify that when we're at the bottom of the list, we can't scroll down but we can scroll
+        // up.
+        assertFalse(mListView.canScrollList(1));
+        assertTrue(mListView.canScrollList(-1));
+
+        // Scroll up to the middle of the list
+        final int itemInTheMiddle = itemCount / 2;
+        verifyScrollToPosition(itemInTheMiddle);
+
+        // Verify that when we're in the middle of the list, we can scroll both up and down.
+        assertTrue(mListView.canScrollList(-1));
+        assertTrue(mListView.canScrollList(1));
+    }
+
+    private void verifyScrollBy(int y) {
+        // Here we rely on knowing the fixed pixel height of each row
+        final int startTopPositionInListCoordinates =
+                mListView.getFirstVisiblePosition() * ROW_HEIGHT_PX -
+                        mListView.getChildAt(0).getTop();
+
+        // Since scrollListBy is a synchronous operation, we do not need to wait
+        // until we can proceed to test the result
+        mInstrumentation.runOnMainSync(() -> mListView.scrollListBy(y));
+
+        final int endTopPositionInListCoordinates =
+                mListView.getFirstVisiblePosition() * ROW_HEIGHT_PX -
+                        mListView.getChildAt(0).getTop();
+
+        // As specified in the Javadocs of AbsListView.scrollListBy, the actual scroll amount
+        // will be capped by the list height minus one pixel
+        final int listHeight = mListView.getHeight();
+        final int expectedScrollAmount = (y > 0) ? Math.min(y, listHeight - 1)
+                : Math.max(y, -(listHeight - 1));
+        int expectedTopPositionInListCoordinates =
+                startTopPositionInListCoordinates + expectedScrollAmount;
+        // Need to clamp it to account for requests that would scroll the content outside
+        // of the available bounds
+        expectedTopPositionInListCoordinates = Math.max(0, expectedTopPositionInListCoordinates);
+        expectedTopPositionInListCoordinates = Math.min(
+                COUNTRY_LIST.length * ROW_HEIGHT_PX - mListView.getHeight(),
+                expectedTopPositionInListCoordinates);
+
+        assertEquals(expectedTopPositionInListCoordinates, endTopPositionInListCoordinates);
+    }
+
+    @Test
+    public void testScrollListBy() {
+        final int listHeight = mListView.getHeight();
+        final int itemCount = COUNTRY_LIST.length;
+
+        // Scroll down by half row height
+        verifyScrollBy(ROW_HEIGHT_PX / 2);
+
+        // Scroll up by full row height - verifying that we're going to stop at the top of the first
+        // row
+        verifyScrollBy(-ROW_HEIGHT_PX);
+
+        // Scroll down by slightly more than a screenful of rows - we expect it to be capped
+        // by the list height minus one pixel.
+        verifyScrollBy(listHeight + ROW_HEIGHT_PX);
+
+        // Scroll down by another half row
+        verifyScrollBy(ROW_HEIGHT_PX / 2);
+
+        // Scroll up by full row height
+        verifyScrollBy(-ROW_HEIGHT_PX);
+
+        // Now scroll all the way down (using position-based scrolling)
+        verifyScrollToPosition(itemCount - 1);
+        assertEquals(itemCount - 1, mListView.getLastVisiblePosition());
+
+        // Scroll up by half row height
+        verifyScrollBy(-ROW_HEIGHT_PX / 2);
+
+        // Scroll down by full row height - verifying that we're going to stop at the bottom of the
+        // last row
+        verifyScrollBy(ROW_HEIGHT_PX);
+
+        // Scroll up halfway into the list - we expect it to be capped by the list height minus
+        // one pixel.
+        verifyScrollBy(-itemCount * ROW_HEIGHT_PX / 2);
+    }
+
+    @Test
+    public void testListScrollAndTap() {
+        // Start a programmatic scroll to position 30. We register a scroll listener on the list
+        // to notify us when position 15 becomes visible.
+        final CountDownLatch scrollLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollPositionListListener(scrollLatch, 15));
+        mInstrumentation.runOnMainSync(() -> mListView.smoothScrollToPosition(30));
+
+        boolean result = false;
+        try {
+            // Since position-based scroll is emulated as a series of mini-flings, scrolling
+            // might take considerable time.
+            result = scrollLatch.await(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Timed out while waiting for the scroll to complete", result);
+
+        // Verify that we're here in the middle of the programmatic scroll
+        assertTrue(mListView.getLastVisiblePosition() < 30);
+
+        // Emulate tap in the middle of the list - this should stop our programmatic scroll.
+        // Note that due to asynchronous nature of the moving pieces, we might still get one
+        // more scroll frame as the injected motion events that constitute an emulated tap
+        // are being processed by our list view.
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mListView);
+
+        // Sleep for a second
+        SystemClock.sleep(1000);
+
+        // and verify that we're still haven't scrolled down to position 30
+        assertTrue(mListView.getLastVisiblePosition() < 30);
+    }
+
+    private void verifyListScrollAndEmulateFlingGesture(boolean isDownwardsFlingGesture) {
+        // Start a programmatic scroll to position 30. We register a scroll listener on the list
+        // to notify us when position 15 becomes visible.
+        final CountDownLatch scrollLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollPositionListListener(scrollLatch, 15));
+        mInstrumentation.runOnMainSync(() -> mListView.smoothScrollToPosition(30));
+
+        boolean result = false;
+        try {
+            // Since position-based scroll is emulated as a series of mini-flings, scrolling
+            // might take considerable time.
+            result = scrollLatch.await(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Timed out while waiting for the scroll to complete", result);
+
+        // Verify that we're here in the middle of the programmatic scroll
+        assertTrue(mListView.getLastVisiblePosition() < 30);
+
+        final int firstVisiblePositionBeforeFling = mListView.getFirstVisiblePosition();
+
+        // At this point the programmatic scroll is still going. Now emulate a fling
+        // gesture and verify that we're going to get to the IDLE state
+        final CountDownLatch flingLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(flingLatch));
+        CtsTouchUtils.emulateFlingGesture(mInstrumentation, mListView, isDownwardsFlingGesture);
+
+        try {
+            result = flingLatch.await(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Timed out while waiting for the fling to complete", result);
+
+        // Note that the actual position in the list at the end of the fling depends on
+        // the processing of the injected sequence of motion events that might differ at milli/micro
+        // second level from run to run
+        if (isDownwardsFlingGesture) {
+            // Verify that the fling gesture has been processed, getting us closer to the
+            // beginning of the list.
+            assertTrue(mListView.getFirstVisiblePosition() < firstVisiblePositionBeforeFling);
+        } else {
+            // Verify that the fling gesture has been processed, getting us closer to the
+            // end of the list.
+            assertTrue(mListView.getFirstVisiblePosition() > firstVisiblePositionBeforeFling);
+        }
+    }
+
+    @Test
+    public void testListScrollAndEmulateDownwardsFlingGesture() {
+        verifyListScrollAndEmulateFlingGesture(true);
+    }
+
+    @Test
+    public void testListScrollAndEmulateUpwardsFlingGesture() {
+        verifyListScrollAndEmulateFlingGesture(false);
+    }
+
+    @Test
+    public void testListFlingWithZeroVelocity() {
+        mListView.setVelocityScale(0.0f);
+
+        final CountDownLatch flingLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(flingLatch));
+        final int flingAmount =
+                CtsTouchUtils.emulateFlingGesture(mInstrumentation, mListView, false);
+
+        try {
+            assertTrue("Timed out while waiting for the fling to complete",
+                    flingLatch.await(5, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        // Since our velocity scale is 0, we expect that the emulated fling gesture didn't
+        // result in any fling, but just a simple scroll that stopped at the ACTION_UP
+        // event.
+        final int expectedTopOffsetAtFlingEnd = -flingAmount;
+        final int expectedBottomOffsetAtFlingEnd = mListView.getHeight() - flingAmount;
+        final int expectedTopPositionAtFlingEnd = expectedTopOffsetAtFlingEnd / ROW_HEIGHT_PX;
+        final int expectedBottomPositionAtFlingEnd = expectedBottomOffsetAtFlingEnd / ROW_HEIGHT_PX;
+
+        assertEquals(expectedTopPositionAtFlingEnd, mListView.getFirstVisiblePosition());
+        assertEquals(expectedBottomPositionAtFlingEnd, mListView.getLastVisiblePosition());
+    }
+
+    private static class LargeContentAdapter extends BaseAdapter {
+        private final Context mContext;
+        private final int mCount;
+        private final LayoutInflater mLayoutInflater;
+
+        public LargeContentAdapter(Context context, int count) {
+            mContext = context;
+            mCount = count;
+            mLayoutInflater = LayoutInflater.from(mContext);
+        }
+
+        @Override
+        public int getCount() {
+            return mCount;
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return true;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return null;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final TextView textView = (convertView != null) ? (TextView) convertView
+                    : (TextView) mLayoutInflater.inflate(R.layout.listitemfixed_layout,
+                            parent, false);
+            textView.setText("Item " + position);
+            return textView;
+        }
+    }
+
+    @Test
+    public void testFriction() {
+        // Set an adapter with 100K items so that no matter how fast our fling is, we won't
+        // get to the bottom of the list in one fling
+        mInstrumentation.runOnMainSync(
+                () -> mListView.setAdapter(new LargeContentAdapter(mContext, 100000)));
+        mInstrumentation.waitForIdleSync();
+
+        final CountDownLatch initialFlingLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(initialFlingLatch));
+        CtsTouchUtils.emulateFlingGesture(mInstrumentation, mListView, false);
+        try {
+            assertTrue("Timed out while waiting for the fling to complete",
+                    initialFlingLatch.await(5, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        final int lastVisiblePositionAfterDefaultFling = mListView.getLastVisiblePosition();
+
+        // Scroll back to the top of the list
+        verifyScrollToPosition(0);
+        // configure the fling to have less friction
+        mListView.setFriction(ViewConfiguration.getScrollFriction() / 2.0f);
+        // and do the fling again
+        final CountDownLatch fastFlingLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(fastFlingLatch));
+        CtsTouchUtils.emulateFlingGesture(mInstrumentation, mListView, false);
+        try {
+            assertTrue("Timed out while waiting for the fling to complete",
+                    fastFlingLatch.await(5, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        final int lastVisiblePositionAfterFastFling = mListView.getLastVisiblePosition();
+
+        // We expect a fast fling (with lower scroll friction) to end up scrolling more
+        // of our content
+        assertTrue("Default fling ended at " + lastVisiblePositionAfterDefaultFling
+                        + ", while fast fling ended at " + lastVisiblePositionAfterFastFling,
+                lastVisiblePositionAfterFastFling > lastVisiblePositionAfterDefaultFling);
+
+        // Scroll back to the top of the list
+        verifyScrollToPosition(0);
+        // configure the fling to have more friction
+        mListView.setFriction(ViewConfiguration.getScrollFriction() * 2.0f);
+        // and do the fling again
+        final CountDownLatch slowFlingLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(slowFlingLatch));
+        CtsTouchUtils.emulateFlingGesture(mInstrumentation, mListView, false);
+        try {
+            assertTrue("Timed out while waiting for the fling to complete",
+                    slowFlingLatch.await(5, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        final int lastVisiblePositionAfterSlowFling = mListView.getLastVisiblePosition();
+
+        // We expect a slow fling (with higher scroll friction) to end up scrolling less
+        // of our content
+        assertTrue("Default fling ended at " + lastVisiblePositionAfterDefaultFling
+                        + ", while slow fling ended at " + lastVisiblePositionAfterSlowFling,
+                lastVisiblePositionAfterSlowFling < lastVisiblePositionAfterDefaultFling);
+    }
+}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/AbsSeekBarCtsActivity.java
similarity index 67%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/AbsSeekBarCtsActivity.java
index 481f5be..1bac1f5 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsSeekBarCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.AbsSeekBar;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link AbsSeekBar} test
+ */
+public class AbsSeekBarCtsActivity extends Activity {
+    /**
+     * Called when the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.seekbar_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java b/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java
index 93032f6..94476c8 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java
@@ -16,49 +16,75 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.cts.util.PollingCheck;
-import android.graphics.Canvas;
+import android.cts.util.WidgetTestUtils;
 import android.graphics.Color;
-import android.graphics.ColorFilter;
 import android.graphics.PorterDuff;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.widget.AbsSeekBar;
 import android.widget.SeekBar;
+import android.widget.cts.util.TestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.List;
 
 /**
  * Test {@link AbsSeekBar}.
  */
-public class AbsSeekBarTest extends ActivityInstrumentationTestCase2<ProgressBarCtsActivity> {
-    public AbsSeekBarTest() {
-        super("android.widget.cts", ProgressBarCtsActivity.class);
-    }
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AbsSeekBarTest {
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Rule
+    public ActivityTestRule<AbsSeekBarCtsActivity> mActivityRule
+            = new ActivityTestRule<>(AbsSeekBarCtsActivity.class);
 
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
+    @Test
     public void testConstructor() {
         new MyAbsSeekBar(mActivity);
 
         new MyAbsSeekBar(mActivity, null);
 
         new MyAbsSeekBar(mActivity, null, android.R.attr.progressBarStyle);
+
+        new MyAbsSeekBar(mActivity, null, 0, android.R.style.Widget_Material_Light_ProgressBar);
     }
 
+    @Test
     public void testAccessThumbOffset() {
         AbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
         final int positive = 5;
@@ -75,58 +101,80 @@
         assertEquals(negative, myAbsSeekBar.getThumbOffset());
     }
 
-    public void testSetThumb() {
-        MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
+    @Test
+    public void testAccessThumb() {
+        // Both are pointing to the same object. This works around current limitation in CTS
+        // coverage report tool for properly reporting coverage of base class method calls.
+        final MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
+        final AbsSeekBar absSeekBar = myAbsSeekBar;
+
         Drawable drawable1 = mActivity.getDrawable(R.drawable.scenery);
         Drawable drawable2 = mActivity.getDrawable(R.drawable.pass);
 
         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
 
-        myAbsSeekBar.setThumb(drawable1);
-        assertSame(drawable1, myAbsSeekBar.getThumb());
+        absSeekBar.setThumb(drawable1);
+        assertSame(drawable1, absSeekBar.getThumb());
         assertTrue(myAbsSeekBar.verifyDrawable(drawable1));
         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
 
-        myAbsSeekBar.setThumb(drawable2);
-        assertSame(drawable2, myAbsSeekBar.getThumb());
+        absSeekBar.setThumb(drawable2);
+        assertSame(drawable2, absSeekBar.getThumb());
         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
         assertTrue(myAbsSeekBar.verifyDrawable(drawable2));
     }
 
-    public void testSetTickMark() {
-        MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
+    @Test
+    public void testAccessTickMark() {
+        // Both are pointing to the same object. This works around current limitation in CTS
+        // coverage report tool for properly reporting coverage of base class method calls.
+        final MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
+        final AbsSeekBar absSeekBar = myAbsSeekBar;
+
         Drawable drawable1 = mActivity.getDrawable(R.drawable.black);
         Drawable drawable2 = mActivity.getDrawable(R.drawable.black);
 
         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
 
-        myAbsSeekBar.setTickMark(drawable1);
-        assertSame(drawable1, myAbsSeekBar.getTickMark());
+        absSeekBar.setTickMark(drawable1);
+        assertSame(drawable1, absSeekBar.getTickMark());
         assertTrue(myAbsSeekBar.verifyDrawable(drawable1));
         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
 
-        myAbsSeekBar.setTickMark(drawable2);
-        assertSame(drawable2, myAbsSeekBar.getTickMark());
+        absSeekBar.setTickMark(drawable2);
+        assertSame(drawable2, absSeekBar.getTickMark());
         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
         assertTrue(myAbsSeekBar.verifyDrawable(drawable2));
     }
 
+    @Test
     public void testDrawableStateChanged() {
         MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
-        MockDrawable drawable = new MockDrawable();
-        myAbsSeekBar.setProgressDrawable(drawable);
+        Drawable mockProgressDrawable = spy(new ColorDrawable(Color.YELLOW));
+        myAbsSeekBar.setProgressDrawable(mockProgressDrawable);
 
+        ArgumentCaptor<Integer> alphaCaptor = ArgumentCaptor.forClass(Integer.class);
         myAbsSeekBar.setEnabled(false);
         myAbsSeekBar.drawableStateChanged();
-        assertEquals(0, drawable.getAlpha());
+        verify(mockProgressDrawable, atLeastOnce()).setAlpha(alphaCaptor.capture());
+        // Verify that the last call to setAlpha was with argument 0x00
+        List<Integer> alphaCaptures = alphaCaptor.getAllValues();
+        assertTrue(!alphaCaptures.isEmpty());
+        assertEquals(Integer.valueOf(0x00), alphaCaptures.get(alphaCaptures.size() - 1));
 
+        alphaCaptor = ArgumentCaptor.forClass(Integer.class);
         myAbsSeekBar.setEnabled(true);
         myAbsSeekBar.drawableStateChanged();
-        assertEquals(0xFF, drawable.getAlpha());
+        verify(mockProgressDrawable, atLeastOnce()).setAlpha(alphaCaptor.capture());
+        // Verify that the last call to setAlpha was with argument 0xFF
+        alphaCaptures = alphaCaptor.getAllValues();
+        assertTrue(!alphaCaptures.isEmpty());
+        assertEquals(Integer.valueOf(0xFF), alphaCaptures.get(alphaCaptures.size() - 1));
     }
 
+    @Test
     public void testVerifyDrawable() {
         MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
         Drawable drawable1 = mActivity.getDrawable(R.drawable.scenery);
@@ -160,44 +208,35 @@
         assertTrue(myAbsSeekBar.verifyDrawable(drawable4));
     }
 
-    public void testAccessKeyProgressIncrement() throws Throwable {
+    @Test
+    public void testAccessKeyProgressIncrement() {
         // AbsSeekBar is an abstract class, use its subclass: SeekBar to do this test.
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(R.layout.seekbar_layout);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> mActivity.setContentView(R.layout.seekbar_layout));
+        mInstrumentation.waitForIdleSync();
 
         final SeekBar seekBar = (SeekBar) mActivity.findViewById(R.id.seekBar);
         final int keyProgressIncrement = 2;
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                seekBar.setKeyProgressIncrement(keyProgressIncrement);
-                seekBar.setFocusable(true);
-                seekBar.requestFocus();
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            seekBar.setKeyProgressIncrement(keyProgressIncrement);
+            seekBar.setFocusable(true);
+            seekBar.requestFocus();
         });
-        new PollingCheck(1000) {
-            @Override
-            protected boolean check() {
-                return seekBar.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(1000, seekBar::hasWindowFocus);
         assertEquals(keyProgressIncrement, seekBar.getKeyProgressIncrement());
 
         int oldProgress = seekBar.getProgress();
         KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
-        getInstrumentation().sendKeySync(keyEvent);
+        mInstrumentation.sendKeySync(keyEvent);
         assertEquals(oldProgress + keyProgressIncrement, seekBar.getProgress());
         oldProgress = seekBar.getProgress();
         keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT);
-        getInstrumentation().sendKeySync(keyEvent);
+        mInstrumentation.sendKeySync(keyEvent);
         assertEquals(oldProgress - keyProgressIncrement, seekBar.getProgress());
     }
 
-    public void testSetMax() {
-        MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity, null, R.style.TestProgressBar);
+    @Test
+    public void testAccessMax() {
+        AbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity, null, R.style.TestProgressBar);
 
         int progress = 10;
         myAbsSeekBar.setProgress(progress);
@@ -224,60 +263,81 @@
         assertEquals(keyProgressIncrement + 1, myAbsSeekBar.getKeyProgressIncrement());
     }
 
-    @UiThreadTest
+    @Test
     public void testThumbTint() {
-        mActivity.setContentView(R.layout.seekbar_layout);
-
-        SeekBar inflatedView = (SeekBar) mActivity.findViewById(R.id.thumb_tint);
+        AbsSeekBar inflatedView = (AbsSeekBar) mActivity.findViewById(R.id.thumb_tint);
 
         assertEquals("Thumb tint inflated correctly",
                 Color.WHITE, inflatedView.getThumbTintList().getDefaultColor());
         assertEquals("Thumb tint mode inflated correctly",
                 PorterDuff.Mode.SRC_OVER, inflatedView.getThumbTintMode());
 
-        MockDrawable thumb = new MockDrawable();
-        SeekBar view = new SeekBar(mActivity);
+        Drawable mockThumb = spy(new ColorDrawable(Color.BLUE));
 
-        view.setThumb(thumb);
-        assertFalse("No thumb tint applied by default", thumb.hasCalledSetTint());
+        mInstrumentation.runOnMainSync(() -> inflatedView.setThumb(mockThumb));
+        verify(mockThumb, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
 
-        view.setThumbTintList(ColorStateList.valueOf(Color.WHITE));
-        assertTrue("Thumb tint applied when setThumbTintList() called after setThumb()",
-                thumb.hasCalledSetTint());
+        reset(mockThumb);
+        mInstrumentation.runOnMainSync(
+                () -> inflatedView.setThumbTintList(ColorStateList.valueOf(Color.RED)));
+        verify(mockThumb, times(1)).setTintList(TestUtils.colorStateListOf(Color.RED));
 
-        thumb.reset();
-        view.setThumb(null);
-        view.setThumb(thumb);
-        assertTrue("Thumb tint applied when setThumbTintList() called before setThumb()",
-                thumb.hasCalledSetTint());
+        mInstrumentation.runOnMainSync(
+                () -> inflatedView.setThumbTintMode(PorterDuff.Mode.DST_ATOP));
+        assertEquals("Thumb tint mode changed correctly",
+                PorterDuff.Mode.DST_ATOP, inflatedView.getThumbTintMode());
+
+        reset(mockThumb);
+        mInstrumentation.runOnMainSync(() -> {
+                inflatedView.setThumb(null);
+                inflatedView.setThumb(mockThumb);
+        });
+        verify(mockThumb, times(1)).setTintList(TestUtils.colorStateListOf(Color.RED));
     }
 
-    @UiThreadTest
+    @Test
     public void testTickMarkTint() {
-        mActivity.setContentView(R.layout.seekbar_layout);
-
-        SeekBar inflatedView = (SeekBar) mActivity.findViewById(R.id.tick_mark_tint);
+        AbsSeekBar inflatedView = (AbsSeekBar) mActivity.findViewById(R.id.tick_mark_tint);
 
         assertEquals("TickMark tint inflated correctly",
                 Color.WHITE, inflatedView.getTickMarkTintList().getDefaultColor());
         assertEquals("TickMark tint mode inflated correctly",
                 PorterDuff.Mode.SRC_OVER, inflatedView.getTickMarkTintMode());
 
-        MockDrawable tickMark = new MockDrawable();
-        SeekBar view = new SeekBar(mActivity);
+        Drawable mockTickMark = spy(new ColorDrawable(Color.BLUE));
 
-        view.setTickMark(tickMark);
-        assertFalse("No tickMark tint applied by default", tickMark.hasCalledSetTint());
+        mInstrumentation.runOnMainSync(() -> inflatedView.setTickMark(mockTickMark));
+        verify(mockTickMark, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
 
-        view.setTickMarkTintList(ColorStateList.valueOf(Color.WHITE));
-        assertTrue("TickMark tint applied when setTickMarkTintList() called after setTickMark()",
-                tickMark.hasCalledSetTint());
+        reset(mockTickMark);
+        mInstrumentation.runOnMainSync(
+                () -> inflatedView.setTickMarkTintList(ColorStateList.valueOf(Color.RED)));
+        verify(mockTickMark, times(1)).setTintList(TestUtils.colorStateListOf(Color.RED));
 
-        tickMark.reset();
-        view.setTickMark(null);
-        view.setTickMark(tickMark);
-        assertTrue("TickMark tint applied when setTickMarkTintList() called before setTickMark()",
-                tickMark.hasCalledSetTint());
+        mInstrumentation.runOnMainSync(
+                () -> inflatedView.setTickMarkTintMode(PorterDuff.Mode.DARKEN));
+        assertEquals("TickMark tint mode changed correctly",
+                PorterDuff.Mode.DARKEN, inflatedView.getTickMarkTintMode());
+
+        reset(mockTickMark);
+        mInstrumentation.runOnMainSync(() -> {
+                inflatedView.setTickMark(null);
+                inflatedView.setTickMark(mockTickMark);
+        });
+        verify(mockTickMark, times(1)).setTintList(TestUtils.colorStateListOf(Color.RED));
+    }
+
+    @Test
+    public void testAccessSplitTrack() {
+        AbsSeekBar inflatedView = (AbsSeekBar) mActivity.findViewById(R.id.tick_mark_tint);
+
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, inflatedView,
+                () -> inflatedView.setSplitTrack(true));
+        assertTrue(inflatedView.getSplitTrack());
+
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, inflatedView,
+                () -> inflatedView.setSplitTrack(false));
+        assertFalse(inflatedView.getSplitTrack());
     }
 
     private static class MyAbsSeekBar extends AbsSeekBar {
@@ -293,6 +353,10 @@
             super(context, attrs, defStyle);
         }
 
+        public MyAbsSeekBar(Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
+            super(context, attrs, defStyle, defStyleRes);
+        }
+
         @Override
         protected void drawableStateChanged() {
             super.drawableStateChanged();
@@ -303,45 +367,4 @@
             return super.verifyDrawable(who);
         }
     }
-
-    private static class MockDrawable extends Drawable {
-        private int mAlpha;
-        private boolean mCalledDraw = false;
-        private boolean mCalledSetTint = false;
-
-        @Override
-        public void draw(Canvas canvas) { }
-
-        public void reset() {
-            mCalledDraw = false;
-            mCalledSetTint = false;
-        }
-
-        @Override
-        public int getOpacity() {
-            return 0;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-            mAlpha = alpha;
-        }
-
-        public int getAlpha() {
-            return mAlpha;
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) { }
-
-        @Override
-        public void setTintList(ColorStateList tint) {
-            super.setTintList(tint);
-            mCalledSetTint = true;
-        }
-
-        public boolean hasCalledSetTint() {
-            return mCalledSetTint;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java b/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java
index e07e8b1..0a851de 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java
@@ -16,17 +16,21 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.content.Context;
+import android.app.Activity;
+import android.app.Instrumentation;
 import android.database.DataSetObserver;
 import android.graphics.Rect;
 import android.os.Parcelable;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -39,109 +43,116 @@
 import android.widget.Spinner;
 import android.widget.SpinnerAdapter;
 
-public class AbsSpinnerTest extends ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
-    private Context mContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
-    public AbsSpinnerTest() {
-        super("android.widget.cts", RelativeLayoutCtsActivity.class);
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AbsSpinnerTest {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private AbsSpinner mAbsSpinner;
+
+    @Rule
+    public ActivityTestRule<RelativeLayoutCtsActivity> mActivityRule
+            = new ActivityTestRule<>(RelativeLayoutCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mAbsSpinner = (AbsSpinner) mActivity.findViewById(R.id.spinner1);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
-    }
-
-    @UiThreadTest
+    @Test
     public void testConstructor() {
-        new Spinner(mContext);
+        new Spinner(mActivity);
 
-        new Spinner(mContext, null);
+        new Spinner(mActivity, null);
 
-        new Spinner(mContext, null, android.R.attr.spinnerStyle);
+        new Spinner(mActivity, null, android.R.attr.spinnerStyle);
 
-        new Gallery(mContext);
-        new Gallery(mContext, null);
-        new Gallery(mContext, null, 0);
+        new Gallery(mActivity);
+        new Gallery(mActivity, null);
+        new Gallery(mActivity, null, 0);
 
-        XmlPullParser parser = mContext.getResources().getXml(R.layout.gallery_test);
+        XmlPullParser parser = mActivity.getResources().getXml(R.layout.gallery_test);
         AttributeSet attrs = Xml.asAttributeSet(parser);
-        new Gallery(mContext, attrs);
-        new Gallery(mContext, attrs, 0);
+        new Gallery(mActivity, attrs);
+        new Gallery(mActivity, attrs, 0);
     }
 
-    @UiThreadTest
     /**
      * Check points:
      * 1. Jump to the specific item.
      */
+    @Test
     public void testSetSelectionIntBoolean() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
                 android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        absSpinner.setAdapter(adapter);
-        assertEquals(0, absSpinner.getSelectedItemPosition());
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setAdapter(adapter));
+        assertEquals(0, mAbsSpinner.getSelectedItemPosition());
 
-        absSpinner.setSelection(1, true);
-        assertEquals(1, absSpinner.getSelectedItemPosition());
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setSelection(1, true));
+        assertEquals(1, mAbsSpinner.getSelectedItemPosition());
 
-        absSpinner.setSelection(absSpinner.getCount() - 1, false);
-        assertEquals(absSpinner.getCount() - 1, absSpinner.getSelectedItemPosition());
+        mInstrumentation.runOnMainSync(
+                () -> mAbsSpinner.setSelection(mAbsSpinner.getCount() - 1, false));
+        assertEquals(mAbsSpinner.getCount() - 1, mAbsSpinner.getSelectedItemPosition());
 
         // The animation effect depends on implementation in AbsSpinner's subClass.
         // It is not meaningful to check it.
     }
 
-    @UiThreadTest
     /**
      * Check points:
      * 1. the currently selected item should be the one which set using this method.
      */
+    @Test
     public void testSetSelectionInt() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
                 android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        absSpinner.setAdapter(adapter);
-        assertEquals(0, absSpinner.getSelectedItemPosition());
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setAdapter(adapter));
+        assertEquals(0, mAbsSpinner.getSelectedItemPosition());
 
-        absSpinner.setSelection(1);
-        assertEquals(1, absSpinner.getSelectedItemPosition());
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setSelection(1));
+        assertEquals(1, mAbsSpinner.getSelectedItemPosition());
 
-        absSpinner.setSelection(absSpinner.getCount() - 1);
-        assertEquals(absSpinner.getCount() - 1, absSpinner.getSelectedItemPosition());
+        mInstrumentation.runOnMainSync(
+                () -> mAbsSpinner.setSelection(mAbsSpinner.getCount() - 1));
+        assertEquals(mAbsSpinner.getCount() - 1, mAbsSpinner.getSelectedItemPosition());
     }
 
-    @UiThreadTest
     /**
      * Check points:
      * 1. the adapter returned from getAdapter() should be the one specified using setAdapter().
      * 2. the adapter provides methods to transform spinner items based on their position
      * relative to the selected item.
      */
+    @Test
     public void testAccessAdapter() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
                 android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
 
-        absSpinner.setAdapter(adapter);
-        assertSame(adapter, absSpinner.getAdapter());
-        assertEquals(adapter.getCount(), absSpinner.getCount());
-        assertEquals(0, absSpinner.getSelectedItemPosition());
-        assertEquals(adapter.getItemId(0), absSpinner.getSelectedItemId());
-        absSpinner.setSelection(1);
-        assertEquals(1, absSpinner.getSelectedItemPosition());
-        assertEquals(adapter.getItemId(1), absSpinner.getSelectedItemId());
-
-        // issue 1695243, if adapter is null, NullPointerException will be thrown when do layout.
-        // There is neither limit in code nor description about it in javadoc.
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setAdapter(adapter));
+        assertSame(adapter, mAbsSpinner.getAdapter());
+        assertEquals(adapter.getCount(), mAbsSpinner.getCount());
+        assertEquals(0, mAbsSpinner.getSelectedItemPosition());
+        assertEquals(adapter.getItemId(0), mAbsSpinner.getSelectedItemId());
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setSelection(1));
+        assertEquals(1, mAbsSpinner.getSelectedItemPosition());
+        assertEquals(adapter.getItemId(1), mAbsSpinner.getSelectedItemId());
     }
 
-    @UiThreadTest
+    @Test
     public void testRequestLayout() {
-        AbsSpinner absSpinner = new Spinner(mContext);
+        AbsSpinner absSpinner = new Spinner(mActivity);
         absSpinner.layout(0, 0, 200, 300);
         assertFalse(absSpinner.isLayoutRequested());
 
@@ -149,27 +160,25 @@
         assertTrue(absSpinner.isLayoutRequested());
     }
 
-    @UiThreadTest
     /**
      * Check points:
      * 1. The value returned from getCount() equals the count of Adapter associated with
      * this AdapterView.
      */
+    @Test
     public void testGetCount() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
-
-        ArrayAdapter<CharSequence> adapter1 = ArrayAdapter.createFromResource(mContext,
+        ArrayAdapter<CharSequence> adapter1 = ArrayAdapter.createFromResource(mActivity,
                 android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
 
-        absSpinner.setAdapter(adapter1);
-        assertEquals(adapter1.getCount(), absSpinner.getCount());
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setAdapter(adapter1));
+        assertEquals(adapter1.getCount(), mAbsSpinner.getCount());
 
         CharSequence anotherStringArray[] = { "another array string 1", "another array string 2" };
-        ArrayAdapter<CharSequence> adapter2 = new ArrayAdapter<CharSequence>(mContext,
+        ArrayAdapter<CharSequence> adapter2 = new ArrayAdapter<>(mActivity,
                 android.R.layout.simple_spinner_item, anotherStringArray);
 
-        absSpinner.setAdapter(adapter2);
-        assertEquals(anotherStringArray.length, absSpinner.getCount());
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setAdapter(adapter2));
+        assertEquals(anotherStringArray.length, mAbsSpinner.getCount());
     }
 
     /**
@@ -177,9 +186,9 @@
      * 1. Should return the position of the item which contains the specified point.
      * 2. Should return INVALID_POSITION if the point does not intersect an item
      */
-    @UiThreadTest
+    @Test
     public void testPointToPosition() {
-        AbsSpinner absSpinner = new Gallery(mContext);
+        AbsSpinner absSpinner = new Gallery(mActivity);
         MockSpinnerAdapter adapter = new MockSpinnerAdapter();
         assertEquals(AdapterView.INVALID_POSITION, absSpinner.pointToPosition(10, 10));
 
@@ -212,9 +221,9 @@
      * 1. Should return the view corresponding to the currently selected item.
      * 2. Should return null if nothing is selected.
      */
-    @UiThreadTest
+    @Test
     public void testGetSelectedView() {
-        AbsSpinner absSpinner = new Gallery(mContext);
+        AbsSpinner absSpinner = new Gallery(mActivity);
         MockSpinnerAdapter adapter = new MockSpinnerAdapter();
         assertNull(absSpinner.getSelectedView());
 
@@ -224,46 +233,35 @@
 
         absSpinner.setSelection(1, true);
         assertSame(absSpinner.getChildAt(1), absSpinner.getSelectedView());
-
     }
 
-    @UiThreadTest
     /**
      * Check points:
      * 1. the view's current state saved by onSaveInstanceState() should be correctly restored
      * after onRestoreInstanceState().
      */
+    @Test
     public void testOnSaveAndRestoreInstanceState() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
                 android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        absSpinner.setAdapter(adapter);
-        assertEquals(0, absSpinner.getSelectedItemPosition());
-        assertEquals(adapter.getItemId(0), absSpinner.getSelectedItemId());
-        Parcelable parcelable = absSpinner.onSaveInstanceState();
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setAdapter(adapter));
+        assertEquals(0, mAbsSpinner.getSelectedItemPosition());
+        assertEquals(adapter.getItemId(0), mAbsSpinner.getSelectedItemId());
+        Parcelable parcelable = mAbsSpinner.onSaveInstanceState();
 
-        absSpinner.setSelection(1);
-        assertEquals(1, absSpinner.getSelectedItemPosition());
-        assertEquals(adapter.getItemId(1), absSpinner.getSelectedItemId());
+        mInstrumentation.runOnMainSync(() -> mAbsSpinner.setSelection(1));
+        assertEquals(1, mAbsSpinner.getSelectedItemPosition());
+        assertEquals(adapter.getItemId(1), mAbsSpinner.getSelectedItemId());
 
-        absSpinner.onRestoreInstanceState(parcelable);
-        absSpinner.measure(View.MeasureSpec.EXACTLY, View.MeasureSpec.EXACTLY);
-        absSpinner.layout(absSpinner.getLeft(), absSpinner.getTop(), absSpinner.getRight(),
-                absSpinner.getBottom());
-        assertEquals(0, absSpinner.getSelectedItemPosition());
-        assertEquals(adapter.getItemId(0), absSpinner.getSelectedItemId());
-    }
-
-    public void testGenerateDefaultLayoutParams() {
-//        final MockSpinner absSpinner = new MockSpinner(mContext);
-//        LayoutParams layoutParams = (LayoutParams) absSpinner.generateDefaultLayoutParams();
-//        assertEquals(LayoutParams.MATCH_PARENT, layoutParams.width);
-//        assertEquals(LayoutParams.WRAP_CONTENT, layoutParams.height);
-    }
-
-    public void testOnMeasure() {
-        // onMeasure() is implementation details, do NOT test
+        mInstrumentation.runOnMainSync(() -> {
+                mAbsSpinner.onRestoreInstanceState(parcelable);
+                mAbsSpinner.measure(View.MeasureSpec.EXACTLY, View.MeasureSpec.EXACTLY);
+                mAbsSpinner.layout(mAbsSpinner.getLeft(), mAbsSpinner.getTop(),
+                        mAbsSpinner.getRight(), mAbsSpinner.getBottom());
+        });
+        assertEquals(0, mAbsSpinner.getSelectedItemPosition());
+        assertEquals(adapter.getItemId(0), mAbsSpinner.getSelectedItemId());
     }
 
     /*
@@ -299,7 +297,7 @@
         }
 
         public View getView(int position, View convertView, ViewGroup parent) {
-            return new ImageView(mContext);
+            return new ImageView(mActivity);
         }
 
         public int getViewTypeCount() {
diff --git a/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java b/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java
index a838f65..d1b67eb 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java
@@ -16,43 +16,55 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
 import android.cts.util.WidgetTestUtils;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.ViewGroup;
 import android.widget.AbsoluteLayout;
 import android.widget.AbsoluteLayout.LayoutParams;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
-@SuppressWarnings("deprecation")
-public class AbsoluteLayoutTest extends ActivityInstrumentationTestCase2<CtsActivity> {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AbsoluteLayoutTest {
     private static final int DEFAULT_X      = 5;
     private static final int DEFAULT_Y      = 10;
     private static final int DEFAULT_WIDTH  = 20;
     private static final int DEFAULT_HEIGHT = 30;
 
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
     private MyAbsoluteLayout mMyAbsoluteLayout;
     private LayoutParams mAbsoluteLayoutParams;
 
-    public AbsoluteLayoutTest() {
-        super("android.widget.cts", CtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule
+            = new ActivityTestRule<>(CtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         mMyAbsoluteLayout = new MyAbsoluteLayout(mActivity);
         mAbsoluteLayoutParams = new LayoutParams(DEFAULT_WIDTH, DEFAULT_HEIGHT,
                 DEFAULT_X, DEFAULT_Y);
@@ -64,6 +76,7 @@
         return Xml.asAttributeSet(parser);
     }
 
+    @Test
     public void testConstructor() throws XmlPullParserException, IOException {
         AttributeSet attrs = getAttributeSet();
 
@@ -74,14 +87,7 @@
         new AbsoluteLayout(mActivity, attrs, -1);
     }
 
-    public void testOnMeasure() {
-        // onMeasure() is implementation details, do NOT test
-    }
-
-    public void testOnLayout() {
-        // onMeasure() is implementation details, do NOT test
-    }
-
+    @Test
     public void testCheckLayoutParams() {
         assertTrue(mMyAbsoluteLayout.checkLayoutParams(mAbsoluteLayoutParams));
 
@@ -90,13 +96,10 @@
         assertFalse(mMyAbsoluteLayout.checkLayoutParams(null));
     }
 
+    @Test
     public void testGenerateLayoutParams1() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(R.layout.absolute_layout);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> mActivity.setContentView(R.layout.absolute_layout));
+        mInstrumentation.waitForIdleSync();
         AbsoluteLayout layout = (AbsoluteLayout) mActivity.findViewById(R.id.absolute_view);
         LayoutParams params = (LayoutParams) layout.generateLayoutParams(getAttributeSet());
 
@@ -107,6 +110,7 @@
         assertEquals(0, params.y);
     }
 
+    @Test
     public void testGenerateLayoutParams2() {
         LayoutParams params =
             (LayoutParams) mMyAbsoluteLayout.generateLayoutParams(mAbsoluteLayoutParams);
@@ -115,15 +119,14 @@
         assertEquals(DEFAULT_HEIGHT, params.height);
         assertEquals(0, params.x);
         assertEquals(0, params.y);
-
-        try {
-            mMyAbsoluteLayout.generateLayoutParams((LayoutParams) null);
-            fail("did not throw NullPointerException when ViewGroup.LayoutParams is null.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGenerateLayoutParamsFromNull() {
+        mMyAbsoluteLayout.generateLayoutParams((LayoutParams) null);
+    }
+
+    @Test
     public void testGenerateDefaultLayoutParams() {
         LayoutParams params = (LayoutParams) mMyAbsoluteLayout.generateDefaultLayoutParams();
 
diff --git a/tests/tests/widget/src/android/widget/cts/AbsoluteLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/AbsoluteLayout_LayoutParamsTest.java
index 2723581..53ff4da 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsoluteLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsoluteLayout_LayoutParamsTest.java
@@ -16,23 +16,36 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
+import android.content.Context;
 import android.cts.util.WidgetTestUtils;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.widget.AbsoluteLayout;
 import android.widget.AbsoluteLayout.LayoutParams;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
-@SuppressWarnings("deprecation")
-public class AbsoluteLayout_LayoutParamsTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AbsoluteLayout_LayoutParamsTest {
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
 
     private AttributeSet getAttributeSet() throws XmlPullParserException, IOException {
         XmlPullParser parser = mContext.getResources().getLayout(R.layout.absolute_layout);
@@ -40,6 +53,7 @@
         return Xml.asAttributeSet(parser);
     }
 
+    @Test
     public void testConstructor() throws XmlPullParserException, IOException {
         LayoutParams layoutParams;
 
@@ -58,6 +72,7 @@
         new AbsoluteLayout.LayoutParams(mContext, getAttributeSet());
     }
 
+    @Test
     public void testDebug() {
         LayoutParams layoutParams = new AbsoluteLayout.LayoutParams(1, 2, 3, 4);
         assertNotNull(layoutParams.debug("test: "));
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/ActionMenuViewCtsActivity.java
similarity index 66%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/ActionMenuViewCtsActivity.java
index 481f5be..1b58b63 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ActionMenuViewCtsActivity.java
@@ -14,17 +14,23 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.ActionMenuView;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link ActionMenuView} test.
+ */
+public class ActionMenuViewCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.actionmenuview_layout);
     }
 }
+
diff --git a/tests/tests/widget/src/android/widget/cts/ActionMenuViewTest.java b/tests/tests/widget/src/android/widget/cts/ActionMenuViewTest.java
new file mode 100644
index 0000000..0091074
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ActionMenuViewTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.widget.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
+import android.cts.util.WidgetTestUtils;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.Menu;
+import android.widget.ActionMenuView;
+import android.widget.cts.util.TestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ActionMenuViewTest {
+    private Instrumentation mInstrumentation;
+    private ActionMenuViewCtsActivity mActivity;
+    private ActionMenuView mActionMenuView;
+
+    @Rule
+    public ActivityTestRule<ActionMenuViewCtsActivity> mActivityRule
+            = new ActivityTestRule<>(ActionMenuViewCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mActionMenuView = (ActionMenuView) mActivity.findViewById(R.id.action_menu_view);
+    }
+
+    @Test
+    public void testConstructor() {
+        new ActionMenuView(mActivity);
+
+        new ActionMenuView(mActivity, null);
+    }
+
+    @Test
+    public void testMenuContent() {
+        final Menu menu = mActionMenuView.getMenu();
+        assertNotNull(menu);
+
+        mInstrumentation.runOnMainSync(
+                () -> mActivity.getMenuInflater().inflate(R.menu.toolbar_menu, menu));
+
+        assertEquals(6, menu.size());
+        assertEquals(R.id.action_highlight, menu.getItem(0).getItemId());
+        assertEquals(R.id.action_edit, menu.getItem(1).getItemId());
+        assertEquals(R.id.action_delete, menu.getItem(2).getItemId());
+        assertEquals(R.id.action_ignore, menu.getItem(3).getItemId());
+        assertEquals(R.id.action_share, menu.getItem(4).getItemId());
+        assertEquals(R.id.action_print, menu.getItem(5).getItemId());
+
+        ActionMenuView.OnMenuItemClickListener menuItemClickListener =
+                mock(ActionMenuView.OnMenuItemClickListener.class);
+        mActionMenuView.setOnMenuItemClickListener(menuItemClickListener);
+
+        menu.performIdentifierAction(R.id.action_highlight, 0);
+        verify(menuItemClickListener, times(1)).onMenuItemClick(
+                menu.findItem(R.id.action_highlight));
+
+        menu.performIdentifierAction(R.id.action_share, 0);
+        verify(menuItemClickListener, times(1)).onMenuItemClick(
+                menu.findItem(R.id.action_share));
+    }
+
+    @Test
+    public void testMenuOverflowShowHide() {
+        // Inflate menu and check that we're not showing overflow menu yet
+        mInstrumentation.runOnMainSync(
+                () -> mActivity.getMenuInflater().inflate(
+                        R.menu.toolbar_menu, mActionMenuView.getMenu()));
+        assertFalse(mActionMenuView.isOverflowMenuShowing());
+
+        // Ask to show overflow menu and check that it's showing
+        mInstrumentation.runOnMainSync(mActionMenuView::showOverflowMenu);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActionMenuView.isOverflowMenuShowing());
+
+        // Ask to hide the overflow menu and check that it's not showing
+        mInstrumentation.runOnMainSync(mActionMenuView::hideOverflowMenu);
+        mInstrumentation.waitForIdleSync();
+        assertFalse(mActionMenuView.isOverflowMenuShowing());
+    }
+
+    @Test
+    public void testMenuOverflowSubmenu() {
+        // Inflate menu and check that we're not showing overflow menu yet
+        mInstrumentation.runOnMainSync(
+                () -> mActivity.getMenuInflater().inflate(
+                        R.menu.toolbar_menu, mActionMenuView.getMenu()));
+        assertFalse(mActionMenuView.isOverflowMenuShowing());
+
+        // Ask to show overflow menu and check that it's showing
+        mInstrumentation.runOnMainSync(mActionMenuView::showOverflowMenu);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActionMenuView.isOverflowMenuShowing());
+
+        // Register a mock menu item click listener on the toolbar
+        ActionMenuView.OnMenuItemClickListener menuItemClickListener =
+                mock(ActionMenuView.OnMenuItemClickListener.class);
+        mActionMenuView.setOnMenuItemClickListener(menuItemClickListener);
+
+        final Menu menu = mActionMenuView.getMenu();
+
+        // Ask to "perform" the share action and check that the menu click listener has
+        // been notified
+        mInstrumentation.runOnMainSync(() -> menu.performIdentifierAction(R.id.action_share, 0));
+        verify(menuItemClickListener, times(1)).onMenuItemClick(
+                menu.findItem(R.id.action_share));
+
+        // Ask to dismiss all the popups and check that we're not showing the overflow menu
+        mInstrumentation.runOnMainSync(mActionMenuView::dismissPopupMenus);
+        mInstrumentation.waitForIdleSync();
+        assertFalse(mActionMenuView.isOverflowMenuShowing());
+    }
+
+    @Test
+    public void testMenuOverflowIcon() {
+        // Inflate menu and check that we're not showing overflow menu yet
+        mInstrumentation.runOnMainSync(
+                () -> mActivity.getMenuInflater().inflate(
+                        R.menu.toolbar_menu, mActionMenuView.getMenu()));
+
+        final Drawable overflowIcon = mActivity.getDrawable(R.drawable.icon_red);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mActionMenuView,
+                () -> mActionMenuView.setOverflowIcon(overflowIcon));
+
+        final Drawable toolbarOverflowIcon = mActionMenuView.getOverflowIcon();
+        TestUtils.assertAllPixelsOfColor("Overflow icon is red", toolbarOverflowIcon,
+                toolbarOverflowIcon.getIntrinsicWidth(), toolbarOverflowIcon.getIntrinsicHeight(),
+                true, Color.RED, 1, false);
+    }
+
+    @Test
+    public void testPopupTheme() {
+        mInstrumentation.runOnMainSync(() -> {
+                mActivity.getMenuInflater().inflate(R.menu.toolbar_menu, mActionMenuView.getMenu());
+                mActionMenuView.setPopupTheme(R.style.ToolbarPopupTheme_Test);
+        });
+        assertEquals(R.style.ToolbarPopupTheme_Test, mActionMenuView.getPopupTheme());
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/AdapterViewCtsActivity.java
index a85e365..6e8e7ed 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewCtsActivity.java
@@ -16,17 +16,16 @@
 
 package android.widget.cts;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.ArrayAdapter;
 import android.widget.ListView;
-
 import android.widget.cts.R;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A minimal application for AdapterView test.
  */
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
index 1b9137f..7c49f1b 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
@@ -16,12 +16,32 @@
 
 package android.widget.cts;
 
-import org.xmlpull.v1.XmlPullParser;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
 
-import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
+import android.cts.util.WidgetTestUtils;
 import android.os.Parcelable;
-import android.test.ActivityInstrumentationTestCase2;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.util.Xml;
@@ -31,18 +51,20 @@
 import android.view.animation.LayoutAnimationController;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.ListAdapter;
 import android.widget.ListView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView.OnItemLongClickListener;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.provider.Settings;
 
-import android.widget.cts.R;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
-
-public class AdapterViewTest extends ActivityInstrumentationTestCase2<AdapterViewCtsActivity> {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AdapterViewTest {
 
     private final static int INVALID_ID = -1;
 
@@ -51,20 +73,20 @@
 
     final String[] FRUIT = { "1", "2", "3", "4", "5", "6", "7", "8" };
 
-    private Activity mActivity;
+    private AdapterViewCtsActivity mActivity;
     private AdapterView<ListAdapter> mAdapterView;
 
-    public AdapterViewTest() {
-        super("android.widget.cts", AdapterViewCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<AdapterViewCtsActivity> mActivityRule
+            = new ActivityTestRule<>(AdapterViewCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
         mAdapterView = new ListView(mActivity);
     }
 
+    @Test
     public void testConstructor() {
         XmlPullParser parser = mActivity.getResources().getXml(R.layout.adapterview_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -75,83 +97,60 @@
 
         new MockAdapterView(mActivity, attrs, 0);
 
-        try {
-            new MockAdapterView(null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-            //expected
-        }
-
         new MockAdapterView(mActivity, null, INVALID_ID);
     }
 
-    /**
-     * test not supported methods, all should throw UnsupportedOperationException
-     */
-    public void testUnsupportedMethods() {
-        ListView subView = new ListView(mActivity);
-
-        try {
-            mAdapterView.addView(subView);
-            fail("addView(View) is not supported in AdapterView.");
-        } catch (UnsupportedOperationException e) {
-            //expected
-        }
-
-        try {
-            mAdapterView.addView(subView, 0);
-            fail("addView(View, int) is not supported in AdapterView.");
-        } catch (UnsupportedOperationException e) {
-            //expected
-        }
-
-        try {
-            mAdapterView.addView(subView, (ViewGroup.LayoutParams) null);
-            fail("addView(View, ViewGroup.LayoutParams) is not supported in AdapterView.");
-        } catch (UnsupportedOperationException e) {
-            //expected
-        }
-
-        try {
-            mAdapterView.addView(subView, 0, (ViewGroup.LayoutParams) null);
-            fail("addView(View, int, ViewGroup.LayoutParams) is not supported in AdapterView.");
-        } catch (UnsupportedOperationException e) {
-            //expected
-        }
-
-        try {
-            mAdapterView.removeViewAt(0);
-            fail("removeViewAt(int) is not supported in AdapterView");
-        } catch (UnsupportedOperationException e) {
-            //expected
-        }
-
-        try {
-            mAdapterView.removeAllViews();
-            fail("removeAllViews() is not supported in AdapterView");
-        } catch (UnsupportedOperationException e) {
-            //expected
-        }
-
-        try {
-            mAdapterView.removeView(subView);
-            fail("removeView(View) is not supported in AdapterView");
-        } catch (UnsupportedOperationException e) {
-            //expected
-        }
-
-        try {
-            mAdapterView.setOnClickListener(new android.view.View.OnClickListener() {
-                public void onClick(View v) {
-                }
-            });
-            fail("function setOnClickListener(android.view.View.OnClickListener) "
-                    + "should throw out runtime exception");
-        } catch (RuntimeException e) {
-            // expected
-        }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext() {
+        new MockAdapterView(null);
     }
 
+    @Test(expected=UnsupportedOperationException.class)
+    public void testAddView1() {
+        ListView subView = new ListView(mActivity);
+        mAdapterView.addView(subView);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testAddView2() {
+        ListView subView = new ListView(mActivity);
+        mAdapterView.addView(subView, 0);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testAddView3() {
+        ListView subView = new ListView(mActivity);
+        mAdapterView.addView(subView, (ViewGroup.LayoutParams) null);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testAddView4() {
+        ListView subView = new ListView(mActivity);
+        mAdapterView.addView(subView, 0, (ViewGroup.LayoutParams) null);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testRemoveView1() {
+        mAdapterView.removeViewAt(0);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testRemoveView2() {
+        ListView subView = new ListView(mActivity);
+        mAdapterView.removeView(subView);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testRemoveAllViews() {
+        mAdapterView.removeAllViews();
+    }
+
+    @Test(expected=RuntimeException.class)
+    public void testSetOnClickListener() {
+        mAdapterView.setOnClickListener((View v) -> {});
+    }
+
+    @Test
     public void testGetCount() {
         // Before setAdapter, the count should be zero.
         assertEquals(0, mAdapterView.getCount());
@@ -162,6 +161,7 @@
         assertEquals(FRUIT.length, mAdapterView.getCount());
     }
 
+    @Test
     public void testAccessEmptyView() {
         ImageView emptyView = new ImageView(mActivity);
 
@@ -203,8 +203,8 @@
         assertEquals(View.VISIBLE, emptyView.getVisibility());
     }
 
+    @Test
     public void testAccessVisiblePosition() {
-
         assertEquals(0, mAdapterView.getFirstVisiblePosition());
         // If no adapter has been set, the value should be -1;
         assertEquals(-1, mAdapterView.getLastVisiblePosition());
@@ -212,7 +212,8 @@
         setArrayAdapter(mAdapterView);
 
         // LastVisiblePosition should be adapter's getCount - 1,by mocking method
-        float fontScale = Settings.System.getFloat(mActivity.getContentResolver(), Settings.System.FONT_SCALE, 1);
+        float fontScale = Settings.System.getFloat(
+                mActivity.getContentResolver(), Settings.System.FONT_SCALE, 1);
         if (fontScale < 1) {
             fontScale = 1;
         }
@@ -222,6 +223,7 @@
         assertEquals(FRUIT.length - 1, mAdapterView.getLastVisiblePosition());
     }
 
+    @Test
     public void testItemOrItemIdAtPosition() {
         // no adapter set
         assertNull(mAdapterView.getItemAtPosition(0));
@@ -235,12 +237,6 @@
             assertEquals(FRUIT[i], mAdapterView.getItemAtPosition(i));
         }
         assertNull(mAdapterView.getItemAtPosition(-1));
-        try {
-            mAdapterView.getItemAtPosition(FRUIT.length);
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-            //expected
-        }
 
         for (int i = 0; i < count; i++) {
             assertEquals(i, mAdapterView.getItemIdAtPosition(i));
@@ -249,48 +245,76 @@
         assertEquals(FRUIT.length, mAdapterView.getItemIdAtPosition(FRUIT.length));
     }
 
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testItemAtPositionInvalidIndex() {
+        setArrayAdapter(mAdapterView);
+        mAdapterView.getItemAtPosition(FRUIT.length);
+    }
+
+    @Test
     public void testAccessOnItemClickAndLongClickListener() {
-        MockOnItemClickListener clickListener = new MockOnItemClickListener();
-        MockOnItemLongClickListener longClickListener = new MockOnItemLongClickListener();
+        AdapterView.OnItemClickListener mockClickListener =
+                mock(AdapterView.OnItemClickListener.class);
+        AdapterView.OnItemLongClickListener mockLongClickListener =
+                mock(AdapterView.OnItemLongClickListener.class);
+        when(mockLongClickListener.onItemLongClick(
+                any(AdapterView.class), any(View.class), anyInt(), anyLong())).thenReturn(true);
+
+        assertNull(mAdapterView.getOnItemLongClickListener());
+        assertNull(mAdapterView.getOnItemClickListener());
 
         assertFalse(mAdapterView.performItemClick(null, 0, 0));
 
-        mAdapterView.setOnItemClickListener(clickListener);
-        mAdapterView.setOnItemLongClickListener(longClickListener);
+        mAdapterView.setOnItemClickListener(mockClickListener);
+        mAdapterView.setOnItemLongClickListener(mockLongClickListener);
+        assertEquals(mockLongClickListener, mAdapterView.getOnItemLongClickListener());
 
-        assertFalse(clickListener.isClicked());
+        verifyZeroInteractions(mockClickListener);
         assertTrue(mAdapterView.performItemClick(null, 0, 0));
-        assertTrue(clickListener.isClicked());
+        verify(mockClickListener, times(1)).onItemClick(eq(mAdapterView), any(View.class),
+                eq(0), eq(0L));
 
         setArrayAdapter(mAdapterView);
-        assertFalse(longClickListener.isClicked());
+        verifyZeroInteractions(mockLongClickListener);
         mAdapterView.layout(0, 0, LAYOUT_WIDTH, LAYOUT_HEIGHT);
         assertTrue(mAdapterView.showContextMenuForChild(mAdapterView.getChildAt(0)));
-        assertTrue(longClickListener.isClicked());
+        verify(mockLongClickListener, times(1)).onItemLongClick(eq(mAdapterView), any(View.class),
+                eq(0), eq(0L));
     }
 
+    @Test
     public void testAccessOnItemSelectedListener() {
-        // FIXME: we can not select the item in touch mode, how can we change the mode to test
-        setArrayAdapter(mAdapterView);
-        MockOnItemSelectedListener selectedListener = new MockOnItemSelectedListener();
-        mAdapterView.setOnItemSelectedListener(selectedListener);
+        mAdapterView = mActivity.getListView();
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mAdapterView,
+                () -> mAdapterView.setLayoutParams(new FrameLayout.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.MATCH_PARENT)));
 
-//        mAdapterView.layout(0, 0, LAYOUT_WIDTH, LAYOUT_HEIGHT);
-//
-//        assertFalse(selectedListener.isItemSelected());
-//        assertFalse(selectedListener.isNothingSelected());
-//
-//        mAdapterView.setSelection(1);
-//        assertTrue(selectedListener.isItemSelected());
-//        assertFalse(selectedListener.isNothingSelected());
-//
-//        mAdapterView.setSelection(-1);
-//        assertTrue(selectedListener.isItemSelected());
-//        assertTrue(selectedListener.isNothingSelected());
-//
-//        mAdapterView.setSelection(FRUIT.length);
-//        assertTrue(selectedListener.isItemSelected());
-//        assertTrue(selectedListener.isNothingSelected());
+        instrumentation.runOnMainSync(() -> setArrayAdapter(mAdapterView));
+
+        AdapterView.OnItemSelectedListener mockSelectedListener =
+                mock(AdapterView.OnItemSelectedListener.class);
+        mAdapterView.setOnItemSelectedListener(mockSelectedListener);
+        assertEquals(mockSelectedListener, mAdapterView.getOnItemSelectedListener());
+
+        verifyZeroInteractions(mockSelectedListener);
+
+        // Select item #1 and verify that the listener has been notified
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mAdapterView,
+                () -> mAdapterView.setSelection(1));
+        verify(mockSelectedListener, times(1)).onItemSelected(eq(mAdapterView), any(View.class),
+                eq(1), eq(1L));
+        verifyNoMoreInteractions(mockSelectedListener);
+
+        // Select last item and verify that the listener has been notified
+        reset(mockSelectedListener);
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mAdapterView,
+                () -> mAdapterView.setSelection(FRUIT.length - 1));
+        verify(mockSelectedListener, times(1)).onItemSelected(
+                eq(mAdapterView), any(View.class), eq(FRUIT.length - 1),
+                eq((long) FRUIT.length - 1));
+        verifyNoMoreInteractions(mockSelectedListener);
     }
 
     /*
@@ -301,6 +325,7 @@
      * it's hard to scroll the list in unit test, so we just test without scrolling
      * this means the position of item is same as position of the children in parent layout
      */
+    @Test
     public void testGetPositionForView() {
         setArrayAdapter(mAdapterView);
         mAdapterView.layout(0, 0, LAYOUT_WIDTH, LAYOUT_HEIGHT);
@@ -310,17 +335,18 @@
             assertEquals(i, mAdapterView.getPositionForView(mAdapterView.getChildAt(i)));
         }
 
-        try {
-            assertEquals(AdapterView.INVALID_POSITION, mAdapterView.getPositionForView(null));
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-            //expected
-        }
-
         assertEquals(AdapterView.INVALID_POSITION,
                 mAdapterView.getPositionForView(new ImageView(mActivity)));
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetPositionForNull() {
+        setArrayAdapter(mAdapterView);
+        mAdapterView.layout(0, 0, LAYOUT_WIDTH, LAYOUT_HEIGHT);
+        mAdapterView.getPositionForView(null);
+    }
+
+    @Test
     public void testChangeFocusable() {
         assertFalse(mAdapterView.isFocusable());
         assertFalse(mAdapterView.isFocusableInTouchMode());
@@ -344,16 +370,10 @@
     }
 
     /*
-     * skip this test, no need to test
-     */
-    public void testOnLayout() {
-        // onLayout() is implementation details, do NOT test
-    }
-
-    /*
      * set and get the selected id, position and item.
      * values will not change if invalid id given.
      */
+    @Test
     public void testGetSelected() {
         assertEquals(AdapterView.INVALID_ROW_ID, mAdapterView.getSelectedItemId());
         assertEquals(AdapterView.INVALID_POSITION, mAdapterView.getSelectedItemPosition());
@@ -388,6 +408,7 @@
     /*
      * not update this test until the ViewGroup's test finish.
      */
+    @Test
     public void testDispatchSaveInstanceState() {
         MockAdapterView adapterView = new MockAdapterView(mActivity);
         adapterView.setSaveEnabled(true);
@@ -400,6 +421,7 @@
     /*
      * not update this test until the ViewGroup's test finish.
      */
+    @Test
     public void testDispatchRestoreInstanceState() {
         MockAdapterView adapterView = new MockAdapterView(mActivity);
         adapterView.setSaveEnabled(true);
@@ -413,11 +435,12 @@
      * if no child added, it always return false
      * this method is protected, so we involve the mock
      */
+    @Test
     public void testCanAnimate() {
         MockAdapterView adapterView = new MockAdapterView(mActivity);
         LayoutAnimationController lAC = new LayoutAnimationController(new AnimationSet(true));
 
-            // no child added, always false
+        // no child added, always false
         assertNull(adapterView.getAdapter());
         adapterView.setLayoutAnimation(lAC);
         assertFalse(adapterView.canAnimate());
@@ -459,62 +482,7 @@
     }
 
     private void setArrayAdapter(AdapterView<ListAdapter> adapterView) {
-        ((ListView) adapterView).setAdapter(new ArrayAdapter<String>(
+        adapterView.setAdapter(new ArrayAdapter<>(
                 mActivity, R.layout.adapterview_layout, FRUIT));
     }
-
-    /**
-     * this is a mock item click listener for check out call back
-     */
-    private class MockOnItemClickListener implements OnItemClickListener {
-        private boolean mClicked;
-
-        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-            mClicked = true;
-        }
-
-        protected boolean isClicked() {
-            return mClicked;
-        }
-    }
-
-    /**
-     * this is a mock long item click listener for check out call back
-     */
-    private class MockOnItemLongClickListener implements OnItemLongClickListener {
-        private boolean mClicked;
-
-        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
-            mClicked = true;
-            return true;
-        }
-
-        protected boolean isClicked() {
-            return mClicked;
-        }
-    }
-
-    /**
-     * this is a mock item selected listener for check out call lback
-     */
-    private class MockOnItemSelectedListener implements OnItemSelectedListener {
-        private boolean mIsItemSelected;
-        private boolean mIsNothingSelected;
-
-        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-            mIsItemSelected = true;
-        }
-
-        public void onNothingSelected(AdapterView<?> parent) {
-            mIsNothingSelected = true;
-        }
-
-        protected boolean isItemSelected() {
-            return mIsItemSelected;
-        }
-
-        protected boolean isNothingSelected() {
-            return mIsNothingSelected;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java b/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java
index 17c7a1e..0d6f6a4 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java
@@ -19,7 +19,6 @@
 import android.test.AndroidTestCase;
 import android.view.View;
 import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
 
 public class AdapterView_AdapterContextMenuInfoTest extends AndroidTestCase {
     public void testConstructor() {
diff --git a/tests/tests/widget/src/android/widget/cts/AlphabetIndexerTest.java b/tests/tests/widget/src/android/widget/cts/AlphabetIndexerTest.java
index dd9393c..f217931 100644
--- a/tests/tests/widget/src/android/widget/cts/AlphabetIndexerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AlphabetIndexerTest.java
@@ -16,13 +16,21 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.database.Cursor;
 import android.database.MatrixCursor;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.AlphabetIndexer;
 
-public class AlphabetIndexerTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AlphabetIndexerTest {
     private static final String[] COUNTRIES_LIST = new String[]
         {"Argentina", "Australia", "China", "France", "Germany", "Italy", "Japan", "United States"};
     private static final String[] NAMES_LIST = new String[]
@@ -38,6 +46,7 @@
     private static final int INDEX_OF_MESSI = 5;
     private static final int INDEX_OF_STEVEN = 7;
 
+    @Test
     public void testAlphabetIndexer() {
         Cursor c1 = createCursor("Country", COUNTRIES_LIST);
 
@@ -100,6 +109,7 @@
         assertEquals(NAMES_LIST.length, indexer.getPositionForSection(index));
     }
 
+    @Test
     public void testCompare() {
         Cursor cursor = createCursor("Country", COUNTRIES_LIST);
 
diff --git a/tests/tests/widget/src/android/widget/cts/AnalogClockTest.java b/tests/tests/widget/src/android/widget/cts/AnalogClockTest.java
index fae6516..a63d4b9b 100644
--- a/tests/tests/widget/src/android/widget/cts/AnalogClockTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AnalogClockTest.java
@@ -16,80 +16,56 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.app.Activity;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.widget.AnalogClock;
 
-public class AnalogClockTest extends ActivityInstrumentationTestCase2<FrameLayoutCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AnalogClockTest {
     private AttributeSet mAttrSet;
     private Activity mActivity;
 
-    public AnalogClockTest() {
-        super("android.widget.cts", FrameLayoutCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<FrameLayoutCtsActivity> mActivityRule
+            = new ActivityTestRule<>(FrameLayoutCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        XmlPullParser parser = getActivity().getResources().getXml(R.layout.analogclock);
+    @Before
+    public void setup() throws Exception {
+        mActivity = mActivityRule.getActivity();
+        XmlPullParser parser = mActivity.getResources().getXml(R.layout.analogclock);
         mAttrSet = Xml.asAttributeSet(parser);
-        mActivity = getActivity();
     }
 
-    @UiThreadTest
+    @Test
     public void testConstructor() {
         new AnalogClock(mActivity);
         new AnalogClock(mActivity, mAttrSet);
         new AnalogClock(mActivity, mAttrSet, 0);
-
-        try {
-            new AnalogClock(null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new AnalogClock(null, null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new AnalogClock(null, null, -1);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
-    public void testOnMeasure() {
-        // onMeasure() is implementation details, do NOT test
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new AnalogClock(null);
     }
 
-    public void testOnSizeChanged() {
-        // Do not test onSizeChanged(), implementation details
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new AnalogClock(null, null);
     }
 
-    public void testOnDraw() {
-        // Do not test, it's controlled by View. Implementation details
-    }
-
-    public void testOnDetachedFromWindow() {
-        // Do not test
-    }
-
-    public void testOnAttachedToWindow() {
-        // Do not test
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new AnalogClock(null, null, -1);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
index 03677f2..f09c371 100644
--- a/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
@@ -16,25 +16,38 @@
 
 package android.widget.cts;
 
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
+import android.app.Instrumentation;
 import android.content.Context;
 import android.content.res.Resources.Theme;
 import android.database.DataSetObserver;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.ArrayAdapter;
 import android.widget.Filter;
 import android.widget.TextView;
 
-import android.widget.cts.R;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.List;
 
-public class ArrayAdapterTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ArrayAdapterTest {
 
-    private static final int INVALD_ID = -1;
+    private static final int INVALID_ID = -1;
     private static final String STR1 = "string1";
     private static final String STR2 = "string2";
     private static final String STR3 = "string3";
@@ -42,87 +55,85 @@
     private ArrayAdapter<String> mArrayAdapter;
     private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
-        mArrayAdapter = new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line);
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mArrayAdapter = new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line);
     }
 
+    @Test
     public void testConstructor() {
-
         new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line);
-        new ArrayAdapter<String>(mContext, INVALD_ID);// invalid resource id
+        new ArrayAdapter<String>(mContext, INVALID_ID); // invalid resource id
 
         new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1);
-        new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, INVALD_ID);
+        new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, INVALID_ID);
 
-        new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line,
+        new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line,
                 new String[] {"str1", "str2"});
 
-        new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1,
+        new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1,
                 new String[] {"str1", "str2"});
 
-        List<String> list = new ArrayList<String>();
+        List<String> list = new ArrayList<>();
         list.add(STR1);
         list.add(STR2);
 
-        new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, list);
+        new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line, list);
 
-        new ArrayAdapter<String>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1, list);
-
-        // invalid input
-        try {
-            new ArrayAdapter<String>(null, R.layout.simple_dropdown_item_1line);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-            // expected exception
-        }
+        new ArrayAdapter<>(mContext, R.layout.simple_dropdown_item_1line, R.id.text1, list);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext() {
+        new ArrayAdapter<String>(null, R.layout.simple_dropdown_item_1line);
+    }
+
+    @Test
     public void testDataChangeEvent() {
-        final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver();
+        final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
         mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
 
         // enable automatically notifying.
         mArrayAdapter.setNotifyOnChange(true);
-        assertEquals(0, mockDataSetObserver.getCalledOnChangedCount());
+        verifyZeroInteractions(mockDataSetObserver);
         mArrayAdapter.add(STR1);
         assertEquals(1, mArrayAdapter.getCount());
-        assertEquals(1, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(1)).onChanged();
         mArrayAdapter.add(STR2);
         assertEquals(2, mArrayAdapter.getCount());
-        assertEquals(2, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(2)).onChanged();
 
         // reset data
         mArrayAdapter.clear();
         // clear notify changed
-        assertEquals(3, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(3)).onChanged();
         assertEquals(0, mArrayAdapter.getCount());
         // if empty before, clear also notify changed
         mArrayAdapter.clear();
-        assertEquals(4, mockDataSetObserver.getCalledOnChangedCount());
-        mockDataSetObserver.clearCount();
-        assertEquals(0, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(4)).onChanged();
+
+        reset(mockDataSetObserver);
 
         // disable auto notify
         mArrayAdapter.setNotifyOnChange(false);
 
         mArrayAdapter.add(STR3);
         assertEquals(1, mArrayAdapter.getCount());
-        assertEquals(0, mockDataSetObserver.getCalledOnChangedCount());
+        verifyZeroInteractions(mockDataSetObserver);
 
         // manually notify
         mArrayAdapter.notifyDataSetChanged();
-        assertEquals(1, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(1)).onChanged();
         // no data changed, but force notify
         mArrayAdapter.notifyDataSetChanged();
-        assertEquals(2, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(2)).onChanged();
         // once called notify, auto notify enabled
         mArrayAdapter.add(STR3);
-        assertEquals(3, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(3)).onChanged();
     }
 
+    @Test
     public void testAccessView() {
         final TextView textView = new TextView(mContext);
         textView.setText(STR3);
@@ -145,40 +156,41 @@
         assertSame(textView, mArrayAdapter.getView(0, textView, null));
         assertSame(textView, mArrayAdapter.getDropDownView(0, textView, null));
         assertEquals(STR1, textView.getText());
-
-        try {
-            assertEquals(textView, mArrayAdapter.getView(-1, textView, null));
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            assertEquals(textView, mArrayAdapter.getDropDownView(-1, textView, null));
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            assertEquals(textView,
-                    mArrayAdapter.getView(mArrayAdapter.getCount(), textView, null));
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            assertEquals(textView,
-                    mArrayAdapter.getDropDownView(mArrayAdapter.getCount(), textView, null));
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
-    @UiThreadTest
-    public void testGetFilter() {
-        Filter filter = mArrayAdapter.getFilter();
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetViewOutOfBoundsLow() {
+        final TextView textView = new TextView(mContext);
+        mArrayAdapter.getView(-1, textView, null);
+    }
 
-        assertNotNull(mArrayAdapter.getFilter());
-        assertSame(filter, mArrayAdapter.getFilter());
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDropDownGetViewOutOfBoundsLow() {
+        final TextView textView = new TextView(mContext);
+        mArrayAdapter.getDropDownView(-1, textView, null);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetViewOutOfBoundsHigh() {
+        final TextView textView = new TextView(mContext);
+        mArrayAdapter.getView(mArrayAdapter.getCount(), textView, null);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDropDownGetViewOutOfBoundsHigh() {
+        final TextView textView = new TextView(mContext);
+        mArrayAdapter.getDropDownView(mArrayAdapter.getCount(), textView, null);
+    }
+
+    @Test
+    public void testGetFilter() {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(() -> {
+            Filter filter = mArrayAdapter.getFilter();
+
+            assertNotNull(mArrayAdapter.getFilter());
+            assertSame(filter, mArrayAdapter.getFilter());
+        });
     }
 
     /**
@@ -186,7 +198,8 @@
      * we set a xml that not contain a textview, so exception should throw to lete us know
      * sucessfully change the dropdown xml, but should not affect the normal view by getview
      */
-    public void testSetDropDownViewResouce() {
+    @Test
+    public void testSetDropDownViewResource() {
         mArrayAdapter.add(STR1);
 
         mArrayAdapter.getDropDownView(0, null, null);
@@ -194,17 +207,18 @@
         mArrayAdapter.setDropDownViewResource(R.layout.tabhost_layout);
         // getview is ok
         mArrayAdapter.getView(0, null, null);
-        // getDropDownView error for it changed
-        try {
-            mArrayAdapter.getDropDownView(0, null, null);
-            fail("should throw IllegalStateException");
-        } catch (IllegalStateException e) {
-            // expected exception
-        }
 
-        mArrayAdapter.setDropDownViewResource(INVALD_ID);
+        mArrayAdapter.setDropDownViewResource(INVALID_ID);
     }
 
+    @Test(expected=IllegalStateException.class)
+    public void testSetDropDownViewResourceIllegal() {
+        mArrayAdapter.add(STR1);
+        mArrayAdapter.setDropDownViewResource(R.layout.tabhost_layout);
+        mArrayAdapter.getDropDownView(0, null, null);
+    }
+
+    @Test
     public void testAccessDropDownViewTheme() {
         Theme theme = mContext.getResources().newTheme();
         mArrayAdapter.setDropDownViewTheme(theme);
@@ -215,15 +229,16 @@
      * insert the item to the specific position, notify data changed
      * check -1, normal, > count
      */
+    @Test
     public void testInsert() {
         mArrayAdapter.setNotifyOnChange(true);
-        final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver();
+        final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
         mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
 
         mArrayAdapter.insert(STR1, 0);
         assertEquals(1, mArrayAdapter.getCount());
         assertEquals(0, mArrayAdapter.getPosition(STR1));
-        assertEquals(1, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(1)).onChanged();
 
         mArrayAdapter.insert(STR2, 0);
         assertEquals(2, mArrayAdapter.getCount());
@@ -235,26 +250,31 @@
 
         mArrayAdapter.insert(null, 0);
         assertEquals(0, mArrayAdapter.getPosition(null));
+    }
 
-        try {
-            mArrayAdapter.insert(STR1, -1);
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-            // expected exception
-        }
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testInsertOutOfBoundsLow() {
+        mArrayAdapter.insert(STR1, 0);
+        mArrayAdapter.insert(STR2, 0);
+        mArrayAdapter.insert(null, 0);
 
-        try {
-            mArrayAdapter.insert(STR1, mArrayAdapter.getCount() + 1);
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-            // expected exception
-        }
+        mArrayAdapter.insert(STR1, -1);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testInsertOutOfBoundsHigh() {
+        mArrayAdapter.insert(STR1, 0);
+        mArrayAdapter.insert(STR2, 0);
+        mArrayAdapter.insert(null, 0);
+
+        mArrayAdapter.insert(STR1, mArrayAdapter.getCount() + 1);
     }
 
     /**
      * return the given position obj
      * test range: -1, normal, > count
      */
+    @Test
     public void testGetItem() {
         mArrayAdapter.add(STR1);
         mArrayAdapter.add(STR2);
@@ -263,26 +283,30 @@
         assertSame(STR1, mArrayAdapter.getItem(0));
         assertSame(STR2, mArrayAdapter.getItem(1));
         assertSame(STR3, mArrayAdapter.getItem(2));
+    }
 
-        // test invalid input
-        try {
-            mArrayAdapter.getItem(-1);
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-            // expected exception
-        }
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetItemOutOfBoundsLow() {
+        mArrayAdapter.add(STR1);
+        mArrayAdapter.add(STR2);
+        mArrayAdapter.add(STR3);
 
-        try {
-            mArrayAdapter.getItem(mArrayAdapter.getCount());
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-            // expected exception
-        }
+        mArrayAdapter.getItem(-1);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetItemOutOfBoundsHigh() {
+        mArrayAdapter.add(STR1);
+        mArrayAdapter.add(STR2);
+        mArrayAdapter.add(STR3);
+
+        mArrayAdapter.getItem(mArrayAdapter.getCount());
     }
 
     /**
      * just return the given position
      */
+    @Test
     public void testGetItemId() {
         mArrayAdapter.add(STR1);
         mArrayAdapter.add(STR2);
@@ -294,13 +318,13 @@
 
         // test invalid input
         assertEquals(-1, mArrayAdapter.getItemId(-1));
-        assertEquals(mArrayAdapter.getCount(),
-                mArrayAdapter.getItemId(mArrayAdapter.getCount()));
+        assertEquals(mArrayAdapter.getCount(), mArrayAdapter.getItemId(mArrayAdapter.getCount()));
     }
 
     /*
      * return the obj position that in the array, if there are same objs, return the first one
      */
+    @Test
     public void testGetPosition() {
         mArrayAdapter.add(STR1);
         mArrayAdapter.add(STR2);
@@ -321,24 +345,24 @@
      * Removes the specified object from the array. notify data changed
      * remove first one if duplicated string in the array
      */
+    @Test
     public void testRemove() {
-        final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver();
+        final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
         mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
         mArrayAdapter.setNotifyOnChange(true);
 
         // remove the not exist one
         assertEquals(0, mArrayAdapter.getCount());
-        assertEquals(0, mockDataSetObserver.getCalledOnChangedCount());
+        verifyZeroInteractions(mockDataSetObserver);
         // remove the item not exist also notify change
         mArrayAdapter.remove(STR1);
-        assertEquals(1, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(1)).onChanged();
 
         mArrayAdapter.add(STR1);
         mArrayAdapter.add(STR2);
         mArrayAdapter.add(STR3);
         mArrayAdapter.add(STR2);
-        mockDataSetObserver.clearCount();
-        assertEquals(0, mockDataSetObserver.getCalledOnChangedCount());
+        reset(mockDataSetObserver);
         assertEquals(4, mArrayAdapter.getCount());
 
         mArrayAdapter.remove(STR1);
@@ -346,11 +370,11 @@
         assertEquals(-1, mArrayAdapter.getPosition(STR1));
         assertEquals(0, mArrayAdapter.getPosition(STR2));
         assertEquals(1, mArrayAdapter.getPosition(STR3));
-        assertEquals(1, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(1)).onChanged();
 
         mArrayAdapter.remove(STR2);
         assertEquals(2, mArrayAdapter.getCount());
-        // remove the first one if dumplicated
+        // remove the first one if duplicated
         assertEquals(1, mArrayAdapter.getPosition(STR2));
         assertEquals(0, mArrayAdapter.getPosition(STR3));
 
@@ -364,51 +388,45 @@
      * Creates a new ArrayAdapter from external resources. The content of the array is
      * obtained through {@link android.content.res.Resources#getTextArray(int)}.
      */
+    @Test
     public void testCreateFromResource() {
         ArrayAdapter.createFromResource(mContext, R.array.string, R.layout.simple_spinner_item);
 
-        // invalid input
-        try {
-            ArrayAdapter.createFromResource(null, R.array.string, R.layout.simple_spinner_item);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-            // expected exception
-        }
-
-        try {
-            ArrayAdapter.createFromResource(mContext, INVALD_ID, R.layout.simple_spinner_item);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-            // expected exception
-        }
-
-       ArrayAdapter.createFromResource(mContext, R.array.string, INVALD_ID);
+        ArrayAdapter.createFromResource(mContext, R.array.string, INVALID_ID);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testCreateFromResourceWithNullContext() {
+        ArrayAdapter.createFromResource(null, R.array.string, R.layout.simple_spinner_item);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testCreateFromResourceWithInvalidId() {
+        ArrayAdapter.createFromResource(mContext, INVALID_ID, R.layout.simple_spinner_item);
+    }
+
+    @Test
     public void testSort() {
-        final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver();
+        final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
         mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
         mArrayAdapter.setNotifyOnChange(true);
-        assertEquals(0, mockDataSetObserver.getCalledOnChangedCount());
+        verifyZeroInteractions(mockDataSetObserver);
 
-        mArrayAdapter.sort( new Comparator<String>() {
-            public int compare(String o1, String o2) {
-                return 0;
-            }
-        });
-        assertEquals(1, mockDataSetObserver.getCalledOnChangedCount());
+        mArrayAdapter.sort((String o1, String o2) -> 0);
+        verify(mockDataSetObserver, times(1)).onChanged();
 
         mArrayAdapter.sort(null);
-        assertEquals(2, mockDataSetObserver.getCalledOnChangedCount());
+        verify(mockDataSetObserver, times(2)).onChanged();
     }
 
     /**
      * insert multiple items via add, notify data changed
      * check count and content
      */
+    @Test
     public void testAdd() {
         mArrayAdapter.setNotifyOnChange(true);
-        final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver();
+        final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
         mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
 
         mArrayAdapter.clear();
@@ -425,12 +443,13 @@
      * insert multiple items via addAll, notify data changed
      * check count and content
      */
+    @Test
     public void testAddAllCollection() {
         mArrayAdapter.setNotifyOnChange(true);
-        final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver();
+        final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
         mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
 
-        List<String> list = new ArrayList<String>();
+        List<String> list = new ArrayList<>();
         list.add("");
         list.add("hello");
         list.add("android");
@@ -452,9 +471,10 @@
      * insert multiple items via addAll, notify data changed
      * check count and content
      */
+    @Test
     public void testAddAllParams() {
         mArrayAdapter.setNotifyOnChange(true);
-        final MockDataSetObserver mockDataSetObserver = new MockDataSetObserver();
+        final DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
         mArrayAdapter.registerDataSetObserver(mockDataSetObserver);
 
         mArrayAdapter.clear();
@@ -468,35 +488,4 @@
         assertEquals(mArrayAdapter.getItem(3), "unit");
         assertEquals(mArrayAdapter.getItem(4), "test");
     }
-
-    private static class MockDataSetObserver extends DataSetObserver {
-
-        private int mCalledOnChangedCount;
-        private int mOnCalledInvalidatedCount;
-
-        public MockDataSetObserver() {
-            clearCount();
-        }
-
-        public int getCalledOnChangedCount() {
-            return mCalledOnChangedCount;
-        }
-
-        public int getCalledOnInvalidatedCount() {
-            return mOnCalledInvalidatedCount;
-        }
-
-        public void clearCount() {
-            mCalledOnChangedCount = 0;
-            mOnCalledInvalidatedCount = 0;
-        }
-
-        public void onChanged() {
-            mCalledOnChangedCount++;
-        }
-
-        public void onInvalidated() {
-            mOnCalledInvalidatedCount++;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/AutoCompleteCtsActivity.java b/tests/tests/widget/src/android/widget/cts/AutoCompleteCtsActivity.java
index 1a12d66..38133ca 100644
--- a/tests/tests/widget/src/android/widget/cts/AutoCompleteCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/AutoCompleteCtsActivity.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-
 import android.widget.cts.R;
 
 /**
diff --git a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
index eb22d6b..a46e3eb 100644
--- a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
@@ -16,21 +16,44 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static android.cts.util.WidgetTestUtils.sameCharSequence;
 
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+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.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.UiModeManager;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.cts.util.PollingCheck;
+import android.graphics.Color;
 import android.graphics.Rect;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.graphics.drawable.Drawable;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.Editable;
+import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.KeyCharacterMap;
@@ -40,37 +63,37 @@
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.AutoCompleteTextView;
+import android.widget.AutoCompleteTextView.Validator;
 import android.widget.Filter;
 import android.widget.Filterable;
-import android.widget.AutoCompleteTextView.Validator;
+import android.widget.cts.util.TestUtils;
 
-import java.io.IOException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
-public class AutoCompleteTextViewTest extends
-        ActivityInstrumentationTestCase2<AutoCompleteCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AutoCompleteTextViewTest {
+    private final static String[] WORDS =
+            new String[] { "testOne", "testTwo", "testThree", "testFour" };
+    private final static String STRING_TEST = "To be tested";
+    private final static String STRING_VALIDATED = "String Validated";
+    private final static String STRING_CHECK = "To be checked";
 
-    /**
-     * Instantiates a new text view test.
-     */
-    public AutoCompleteTextViewTest() {
-        super("android.widget.cts", AutoCompleteCtsActivity.class);
-    }
-
-    /** The m activity. */
     private Activity mActivity;
-
-    /** The m instrumentation. */
     private Instrumentation mInstrumentation;
     private AutoCompleteTextView mAutoCompleteTextView;
     private boolean mNumeric = false;
-    ArrayAdapter<String> mAdapter;
-    private final String[] WORDS = new String[] { "testOne", "testTwo", "testThree", "testFour" };
-    boolean isOnFilterComplete = false;
-    final String STRING_TEST = "To be tested";
-    final String STRING_VALIDATED = "String Validated";
-    final String STRING_CHECK = "To be checked";
-    final String STRING_APPEND = "and be appended";
-    Validator mValidator = new Validator() {
+    private ArrayAdapter<String> mAdapter;
+
+    @Rule
+    public ActivityTestRule<AutoCompleteCtsActivity> mActivityRule
+            = new ActivityTestRule<>(AutoCompleteCtsActivity.class);
+
+    private final Validator mValidator = new Validator() {
         public CharSequence fixText(CharSequence invalidText) {
             return STRING_VALIDATED;
         }
@@ -80,22 +103,35 @@
         }
     };
 
-    /*
-     * (non-Javadoc)
-     *
-     * @see android.test.ActivityInstrumentationTestCase#setUp()
-     */
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
-        mInstrumentation = getInstrumentation();
+    protected class MyTextWatcher implements TextWatcher {
+        private CharSequence mExpectedAfter;
+
+        public MyTextWatcher(CharSequence expectedAfter) {
+            mExpectedAfter = expectedAfter;
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+            assertEquals(mExpectedAfter.toString(), s.toString());
+            // This watcher is expected to be notified in the middle of completion
+            assertTrue(mAutoCompleteTextView.isPerformingCompletion());
+        }
+
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+        }
+    }
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
+
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mAutoCompleteTextView = (AutoCompleteTextView) mActivity
                 .findViewById(R.id.autocompletetv_edit);
         mAdapter = new ArrayAdapter<String>(mActivity,
@@ -107,37 +143,41 @@
     }
 
     boolean isTvMode() {
-        UiModeManager uiModeManager = (UiModeManager) getActivity().getSystemService(
+        UiModeManager uiModeManager = (UiModeManager) mActivity.getSystemService(
                 Context.UI_MODE_SERVICE);
         return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
     }
 
-    @UiThreadTest
+    @Test
     public void testConstructor() {
         XmlPullParser parser;
 
-        // new the AutoCompleteTextView instance
         new AutoCompleteTextView(mActivity);
+        new AutoCompleteTextView(mActivity, null);
+        new AutoCompleteTextView(mActivity, null, android.R.attr.autoCompleteTextViewStyle);
+        new AutoCompleteTextView(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_AutoCompleteTextView);
+        new AutoCompleteTextView(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_AutoCompleteTextView);
+        new AutoCompleteTextView(mActivity, null, 0,
+                android.R.style.Widget_Material_AutoCompleteTextView);
+        new AutoCompleteTextView(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_AutoCompleteTextView);
+
+        final Resources.Theme popupTheme = mActivity.getResources().newTheme();
+        popupTheme.applyStyle(android.R.style.Theme_Material, true);
+        new AutoCompleteTextView(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_AutoCompleteTextView, popupTheme);
 
         // new the AutoCompleteTextView instance
         parser = mActivity.getResources().getXml(R.layout.simple_dropdown_item_1line);
         AttributeSet attributeSet = Xml.asAttributeSet(parser);
         new AutoCompleteTextView(mActivity, attributeSet);
-        new AutoCompleteTextView(mActivity, null);
 
         // new the AutoCompleteTextView instance
         parser = mActivity.getResources().getXml(R.layout.framelayout_layout);
         attributeSet = Xml.asAttributeSet(parser);
         new AutoCompleteTextView(mActivity, attributeSet, 0);
-        new AutoCompleteTextView(mActivity, null, 0);
-        // Test constructor with null Context, in fact, previous two functions will
-        // finally invoke this version.
-        try {
-            // Test with null Context
-            new AutoCompleteTextView(null, attributeSet, 0);
-            fail("should throw NullPointerException");
-        } catch (Exception e) {
-        }
 
         // Test for negative style resource ID
         new AutoCompleteTextView(mActivity, attributeSet, -1);
@@ -145,178 +185,256 @@
         new AutoCompleteTextView(mActivity, null, -1);
     }
 
-    public void testEnoughToFilter() throws Throwable {
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext() {
+        XmlPullParser parser = mActivity.getResources().getXml(R.layout.simple_dropdown_item_1line);
+        AttributeSet attributeSet = Xml.asAttributeSet(parser);
+        new AutoCompleteTextView(null, attributeSet, 0);
+    }
+
+    @Test
+    public void testEnoughToFilter() {
         mAutoCompleteTextView.setThreshold(3);
         assertEquals(3, mAutoCompleteTextView.getThreshold());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                String testString = "TryToTest";
-                mAutoCompleteTextView.setText(testString);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText("TryToTest"));
         mInstrumentation.waitForIdleSync();
         assertTrue(mAutoCompleteTextView.enoughToFilter());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                String testString = "No";
-                mAutoCompleteTextView.setText(testString);
-            }
-        });
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText("No"));
         mInstrumentation.waitForIdleSync();
         assertFalse(mAutoCompleteTextView.enoughToFilter());
     }
 
-    @UiThreadTest
+    @Test
     public void testAccessAdapter() {
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(null));
+        assertNull(mAutoCompleteTextView.getAdapter());
+
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(mAdapter));
+        assertSame(mAdapter, mAutoCompleteTextView.getAdapter());
+
+        // Re-set adapter to null
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(null));
+        assertNull(mAutoCompleteTextView.getAdapter());
+    }
+
+    @Test
+    public void testAccessFilter() {
         MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
 
         // Set Threshold to 4 characters
         autoCompleteTextView.setThreshold(4);
 
-        ArrayAdapter<String> adapter = null;
-        autoCompleteTextView.setAdapter(adapter);
+        autoCompleteTextView.setAdapter(null);
         assertNull(autoCompleteTextView.getAdapter());
         assertNull(autoCompleteTextView.getFilter());
 
-        Filter filter = mAdapter.getFilter();
-        assertNotNull(filter);
-        autoCompleteTextView.setAdapter(mAdapter);
-        assertSame(mAdapter, autoCompleteTextView.getAdapter());
-        assertSame(filter, autoCompleteTextView.getFilter());
+        mInstrumentation.runOnMainSync(() -> {
+                Filter filter = mAdapter.getFilter();
+                assertNotNull(filter);
+                autoCompleteTextView.setAdapter(mAdapter);
+                assertSame(mAdapter, autoCompleteTextView.getAdapter());
+                assertSame(filter, autoCompleteTextView.getFilter());
+        });
 
         // Re-set adapter to null
-        autoCompleteTextView.setAdapter(adapter);
+        autoCompleteTextView.setAdapter(null);
         assertNull(autoCompleteTextView.getAdapter());
         assertNull(autoCompleteTextView.getFilter());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testAccessItemClickListener() {
-        final MockOnItemClickListener testOnItemClickListener = new MockOnItemClickListener();
+        final AdapterView.OnItemClickListener mockItemClickListener =
+                mock(AdapterView.OnItemClickListener.class);
 
         // To ensure null listener
         mAutoCompleteTextView.setOnItemClickListener(null);
         assertNull(mAutoCompleteTextView.getItemClickListener());
         assertNull(mAutoCompleteTextView.getOnItemClickListener());
 
-        assertNotNull(testOnItemClickListener);
-        mAutoCompleteTextView.setOnItemClickListener(testOnItemClickListener);
-        assertSame(testOnItemClickListener, mAutoCompleteTextView.getItemClickListener());
-        assertSame(testOnItemClickListener, mAutoCompleteTextView.getOnItemClickListener());
+        mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+        assertSame(mockItemClickListener, mAutoCompleteTextView.getItemClickListener());
+        assertSame(mockItemClickListener, mAutoCompleteTextView.getOnItemClickListener());
+        verifyZeroInteractions(mockItemClickListener);
 
         // re-clear listener by setOnItemClickListener
         mAutoCompleteTextView.setOnItemClickListener(null);
         assertNull(mAutoCompleteTextView.getItemClickListener());
         assertNull(mAutoCompleteTextView.getOnItemClickListener());
+        verifyZeroInteractions(mockItemClickListener);
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testAccessItemSelectedListener() {
-        MockOnItemSelectedListener testOnItemSelectedListener = new MockOnItemSelectedListener();
+        final AdapterView.OnItemSelectedListener mockItemSelectedListener =
+                mock(AdapterView.OnItemSelectedListener.class);
 
         // To ensure null listener
         mAutoCompleteTextView.setOnItemSelectedListener(null);
         assertNull(mAutoCompleteTextView.getItemSelectedListener());
         assertNull(mAutoCompleteTextView.getOnItemSelectedListener());
 
-        assertNotNull(testOnItemSelectedListener);
-        mAutoCompleteTextView.setOnItemSelectedListener(testOnItemSelectedListener);
-        assertSame(testOnItemSelectedListener, mAutoCompleteTextView.getItemSelectedListener());
-        assertSame(testOnItemSelectedListener, mAutoCompleteTextView.getOnItemSelectedListener());
+        mAutoCompleteTextView.setOnItemSelectedListener(mockItemSelectedListener);
+        assertSame(mockItemSelectedListener, mAutoCompleteTextView.getItemSelectedListener());
+        assertSame(mockItemSelectedListener, mAutoCompleteTextView.getOnItemSelectedListener());
+        verifyZeroInteractions(mockItemSelectedListener);
 
         //re-clear listener by setOnItemClickListener
         mAutoCompleteTextView.setOnItemSelectedListener(null);
         assertNull(mAutoCompleteTextView.getItemSelectedListener());
         assertNull(mAutoCompleteTextView.getOnItemSelectedListener());
+        verifyZeroInteractions(mockItemSelectedListener);
     }
 
-    @UiThreadTest
+    @Test
     public void testConvertSelectionToString() {
         MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
 
         // Set Threshold to 4 characters
-        autoCompleteTextView.setThreshold(4);
-        autoCompleteTextView.setAdapter(mAdapter);
+        mInstrumentation.runOnMainSync(() -> {
+                autoCompleteTextView.setThreshold(4);
+                autoCompleteTextView.setAdapter(mAdapter);
+        });
         assertNotNull(autoCompleteTextView.getAdapter());
 
         assertEquals("", autoCompleteTextView.convertSelectionToString(null));
         assertEquals(STRING_TEST, autoCompleteTextView.convertSelectionToString(STRING_TEST));
     }
 
-    @UiThreadTest
+    @Test
     public void testOnTextChanged() {
-        MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
+        final TextWatcher mockTextWatcher = mock(TextWatcher.class);
+        mAutoCompleteTextView.addTextChangedListener(mockTextWatcher);
+        verify(mockTextWatcher, never()).onTextChanged(any(CharSequence.class),
+                anyInt(), anyInt(), anyInt());
 
-        assertFalse(autoCompleteTextView.isOnTextChanged());
-        assertEquals("", autoCompleteTextView.getLastChangeText());
-        assertEquals("", autoCompleteTextView.getText().toString());
-        assertEquals(0, autoCompleteTextView.getStart());
-        assertEquals(0, autoCompleteTextView.getBefore());
-        assertEquals(0, autoCompleteTextView.getAfter());
-
-        autoCompleteTextView.setText(STRING_TEST);
-        assertEquals(STRING_TEST, autoCompleteTextView.getText().toString());
-        assertTrue(autoCompleteTextView.isOnTextChanged());
-        assertEquals(STRING_TEST, autoCompleteTextView.getLastChangeText());
-        assertEquals(0, autoCompleteTextView.getStart());
-        assertEquals(0, autoCompleteTextView.getBefore());
-        assertEquals(STRING_TEST.length(), autoCompleteTextView.getAfter());
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText(STRING_TEST));
+        verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence(STRING_TEST),
+                eq(0), eq(0), eq(STRING_TEST.length()));
 
         // Test replacing text.
-        autoCompleteTextView.resetStatus();
-        autoCompleteTextView.setText(STRING_CHECK);
-        assertEquals(STRING_CHECK, autoCompleteTextView.getText().toString());
-        assertEquals(STRING_CHECK, autoCompleteTextView.getLastChangeText());
-        assertEquals(0, autoCompleteTextView.getStart());
-        assertEquals(STRING_TEST.length(), autoCompleteTextView.getBefore());
-        assertEquals(STRING_CHECK.length(), autoCompleteTextView.getAfter());
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText(STRING_CHECK));
+        verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence(STRING_CHECK),
+                eq(0), eq(STRING_TEST.length()), eq(STRING_CHECK.length()));
     }
 
-    @UiThreadTest
-    public void testPopupWindow() throws XmlPullParserException, IOException {
-        assertFalse(mAutoCompleteTextView.isPopupShowing());
-        mAutoCompleteTextView.showDropDown();
-        assertTrue(mAutoCompleteTextView.isPopupShowing());
+    @Test
+    public void testPopupWindow() {
+        final AutoCompleteTextView.OnDismissListener mockDismissListener =
+                mock(AutoCompleteTextView.OnDismissListener.class);
+        mAutoCompleteTextView.setOnDismissListener(mockDismissListener);
 
-        mAutoCompleteTextView.dismissDropDown();
         assertFalse(mAutoCompleteTextView.isPopupShowing());
-
-        mAutoCompleteTextView.showDropDown();
+        mInstrumentation.runOnMainSync(mAutoCompleteTextView::showDropDown);
         assertTrue(mAutoCompleteTextView.isPopupShowing());
+        verifyZeroInteractions(mockDismissListener);
+
+        mInstrumentation.runOnMainSync(mAutoCompleteTextView::dismissDropDown);
+        assertFalse(mAutoCompleteTextView.isPopupShowing());
+        verify(mockDismissListener, times(1)).onDismiss();
+
+        mInstrumentation.runOnMainSync(mAutoCompleteTextView::showDropDown);
+        assertTrue(mAutoCompleteTextView.isPopupShowing());
+        verify(mockDismissListener, times(1)).onDismiss();
 
         final MockValidator validator = new MockValidator();
         mAutoCompleteTextView.setValidator(validator);
-        mAutoCompleteTextView.requestFocus();
-        mAutoCompleteTextView.showDropDown();
-        assertTrue(mAutoCompleteTextView.isPopupShowing());
-        mAutoCompleteTextView.setText(STRING_TEST);
+        mInstrumentation.runOnMainSync(() -> {
+            mAutoCompleteTextView.requestFocus();
+            mAutoCompleteTextView.showDropDown();
+            mAutoCompleteTextView.setText(STRING_TEST);
+        });
         assertEquals(STRING_TEST, mAutoCompleteTextView.getText().toString());
+
         // clearFocus will trigger onFocusChanged, and onFocusChanged will validate the text.
-        mAutoCompleteTextView.clearFocus();
+        mInstrumentation.runOnMainSync(mAutoCompleteTextView::clearFocus);
         assertFalse(mAutoCompleteTextView.isPopupShowing());
         assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
+        verify(mockDismissListener, times(2)).onDismiss();
+
+        verifyNoMoreInteractions(mockDismissListener);
     }
 
-    @UiThreadTest
+    @Test
+    public void testDropDownMetrics() {
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(mAdapter));
+
+        final Resources res = mActivity.getResources();
+        final int dropDownWidth =
+                res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_width);
+        final int dropDownHeight =
+                res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_height);
+        final int dropDownOffsetHorizontal =
+                res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_offset_h);
+        final int dropDownOffsetVertical =
+                res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_offset_v);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mAutoCompleteTextView.setDropDownWidth(dropDownWidth);
+            mAutoCompleteTextView.setDropDownHeight(dropDownHeight);
+            mAutoCompleteTextView.setDropDownHorizontalOffset(dropDownOffsetHorizontal);
+            mAutoCompleteTextView.setDropDownVerticalOffset(dropDownOffsetVertical);
+
+            mAutoCompleteTextView.showDropDown();
+        });
+
+        assertEquals(dropDownWidth, mAutoCompleteTextView.getDropDownWidth());
+        assertEquals(dropDownHeight, mAutoCompleteTextView.getDropDownHeight());
+        assertEquals(dropDownOffsetHorizontal, mAutoCompleteTextView.getDropDownHorizontalOffset());
+        assertEquals(dropDownOffsetVertical, mAutoCompleteTextView.getDropDownVerticalOffset());
+    }
+
+    @Test
+    public void testDropDownBackground() {
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(mAdapter));
+
+        mInstrumentation.runOnMainSync(() -> {
+            mAutoCompleteTextView.setDropDownBackgroundResource(R.drawable.blue_fill);
+            mAutoCompleteTextView.showDropDown();
+        });
+        mInstrumentation.waitForIdleSync();
+
+        Drawable dropDownBackground = mAutoCompleteTextView.getDropDownBackground();
+        TestUtils.assertAllPixelsOfColor("Drop down should be blue", dropDownBackground,
+                dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
+                false, Color.BLUE, 1, true);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mAutoCompleteTextView.dismissDropDown();
+            mAutoCompleteTextView.setDropDownBackgroundDrawable(
+                    mActivity.getDrawable(R.drawable.yellow_fill));
+            mAutoCompleteTextView.showDropDown();
+        });
+        mInstrumentation.waitForIdleSync();
+
+        dropDownBackground = mAutoCompleteTextView.getDropDownBackground();
+        TestUtils.assertAllPixelsOfColor("Drop down should be yellow", dropDownBackground,
+                dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
+                false, Color.YELLOW, 1, true);
+    }
+
+    @Test
     public void testReplaceText() {
         MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
+        final TextWatcher mockTextWatcher = mock(TextWatcher.class);
+        autoCompleteTextView.addTextChangedListener(mockTextWatcher);
+        verify(mockTextWatcher, never()).onTextChanged(any(CharSequence.class),
+                anyInt(), anyInt(), anyInt());
 
-        assertEquals("", autoCompleteTextView.getText().toString());
-        assertFalse(autoCompleteTextView.isOnTextChanged());
         autoCompleteTextView.replaceText("Text");
         assertEquals("Text", autoCompleteTextView.getText().toString());
-        assertTrue(autoCompleteTextView.isOnTextChanged());
+        verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("Text"),
+                eq(0), eq(0), eq("Text".length()));
 
-        autoCompleteTextView.resetStatus();
-        assertFalse(autoCompleteTextView.isOnTextChanged());
         autoCompleteTextView.replaceText("Another");
         assertEquals("Another", autoCompleteTextView.getText().toString());
-        assertTrue(autoCompleteTextView.isOnTextChanged());
+        verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("Another"),
+                eq(0), eq("Text".length()), eq("Another".length()));
     }
 
-    @UiThreadTest
+    @Test
     public void testSetFrame() {
         MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
 
@@ -341,24 +459,22 @@
         assertEquals(5, autoCompleteTextView.getBottom());
     }
 
+    @Test
     public void testGetThreshold() {
-        final AutoCompleteTextView autoCompleteTextView = (AutoCompleteTextView) mActivity
-                .findViewById(R.id.autocompletetv_edit);
-        assertNotNull(autoCompleteTextView);
-
-        assertEquals(1, autoCompleteTextView.getThreshold());
-        autoCompleteTextView.setThreshold(3);
-        assertEquals(3, autoCompleteTextView.getThreshold());
+        assertEquals(1, mAutoCompleteTextView.getThreshold());
+        mAutoCompleteTextView.setThreshold(3);
+        assertEquals(3, mAutoCompleteTextView.getThreshold());
 
         // Test negative value input
-        autoCompleteTextView.setThreshold(-5);
-        assertEquals(1, autoCompleteTextView.getThreshold());
+        mAutoCompleteTextView.setThreshold(-5);
+        assertEquals(1, mAutoCompleteTextView.getThreshold());
 
         // Test zero
-        autoCompleteTextView.setThreshold(0);
-        assertEquals(1, autoCompleteTextView.getThreshold());
+        mAutoCompleteTextView.setThreshold(0);
+        assertEquals(1, mAutoCompleteTextView.getThreshold());
     }
 
+    @Test
     public void testAccessValidater() {
         final MockValidator validator = new MockValidator();
 
@@ -371,7 +487,8 @@
         assertNull(mAutoCompleteTextView.getValidator());
     }
 
-    public void testOnFilterComplete() throws Throwable {
+    @Test
+    public void testOnFilterComplete() {
         // Set Threshold to 4 characters
         mAutoCompleteTextView.setThreshold(4);
 
@@ -384,22 +501,15 @@
         }
 
         // Test the filter if the input string is not long enough to threshold
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mInstrumentation.runOnMainSync(() -> {
                 mAutoCompleteTextView.setAdapter(mAdapter);
                 mAutoCompleteTextView.setText("");
                 mAutoCompleteTextView.requestFocus();
-            }
         });
         mInstrumentation.sendStringSync(testString);
 
         // onFilterComplete will close the popup.
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !mAutoCompleteTextView.isPopupShowing();
-            }
-        }.run();
+        PollingCheck.waitFor(() -> !mAutoCompleteTextView.isPopupShowing());
 
         if (mNumeric) {
             // "that" in case of 12-key(NUMERIC) keyboard
@@ -408,20 +518,13 @@
             testString = "that";
         }
         mInstrumentation.sendStringSync(testString);
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !mAutoCompleteTextView.isPopupShowing();
-            }
-        }.run();
+        PollingCheck.waitFor(() -> !mAutoCompleteTextView.isPopupShowing());
 
         // Test the expected filter matching scene
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mInstrumentation.runOnMainSync(() -> {
                 mAutoCompleteTextView.setFocusable(true);
                 mAutoCompleteTextView.requestFocus();
                 mAutoCompleteTextView.setText("");
-            }
         });
         if (mNumeric) {
             // "test" in case of 12-key(NUMERIC) keyboard
@@ -431,20 +534,15 @@
         }
         assertTrue(mAutoCompleteTextView.hasFocus());
         assertTrue(mAutoCompleteTextView.hasWindowFocus());
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mAutoCompleteTextView.isPopupShowing();
-            }
-        }.run();
+        PollingCheck.waitFor(() -> mAutoCompleteTextView.isPopupShowing());
     }
 
-    public void testPerformFiltering() throws Throwable {
+    @Test
+    public void testPerformFiltering() {
         if (isTvMode()) {
             return;
         }
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mInstrumentation.runOnMainSync(() -> {
                 mAutoCompleteTextView.setAdapter(mAdapter);
                 mAutoCompleteTextView.setValidator(mValidator);
 
@@ -452,7 +550,6 @@
                 mAutoCompleteTextView.setFocusable(true);
                 mAutoCompleteTextView.requestFocus();
                 mAutoCompleteTextView.showDropDown();
-            }
         });
         mInstrumentation.waitForIdleSync();
         assertTrue(mAutoCompleteTextView.isPopupShowing());
@@ -461,11 +558,9 @@
         // KeyBack will close the popup.
         assertFalse(mAutoCompleteTextView.isPopupShowing());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mInstrumentation.runOnMainSync(() -> {
                 mAutoCompleteTextView.dismissDropDown();
                 mAutoCompleteTextView.setText(STRING_TEST);
-            }
         });
         mInstrumentation.waitForIdleSync();
 
@@ -478,12 +573,10 @@
                 android.R.layout.simple_dropdown_item_1line, WORDS);
 
         // Set Threshold to 4 charactersonKeyDown
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mInstrumentation.runOnMainSync(() -> {
                 mAutoCompleteTextView.setAdapter(adapter);
                 mAutoCompleteTextView.requestFocus();
                 mAutoCompleteTextView.setText("");
-            }
         });
         mInstrumentation.waitForIdleSync();
         // Create and get the filter.
@@ -495,38 +588,28 @@
         if (mNumeric) {
             // "numeric" in case of 12-key(NUMERIC) keyboard
             mInstrumentation.sendStringSync("6688633777444222");
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return "numeric".equals(filter.getResult());
-                }
-            }.run();
+            PollingCheck.waitFor(() -> "numeric".equals(filter.getResult()));
         } else {
-            Thread.sleep(200);
+            SystemClock.sleep(200);
             mInstrumentation.sendStringSync(STRING_TEST);
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return STRING_TEST.equals(filter.getResult());
-                }
-            }.run();
+            PollingCheck.waitFor(() -> STRING_TEST.equals(filter.getResult()));
         }
     }
 
-    public void testPerformCompletion() throws Throwable {
+    @Test
+    public void testPerformCompletionWithDPad() {
         if (isTvMode()) {
             return;
         }
-        final MockOnItemClickListener listener = new MockOnItemClickListener();
+        final AdapterView.OnItemClickListener mockItemClickListener =
+                mock(AdapterView.OnItemClickListener.class);
         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAutoCompleteTextView.setOnItemClickListener(listener);
-                mAutoCompleteTextView.setAdapter(mAdapter);
-                mAutoCompleteTextView.requestFocus();
-                mAutoCompleteTextView.showDropDown();
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.requestFocus();
+            mAutoCompleteTextView.showDropDown();
         });
         mInstrumentation.waitForIdleSync();
         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
@@ -535,102 +618,153 @@
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
         mInstrumentation.waitForIdleSync();
-        assertTrue(listener.isOnItemClicked());
-
+        verify(mockItemClickListener, times(1)).onItemClick(any(AdapterView.class), any(View.class),
+                eq(0), eq(0L));
         assertEquals(WORDS[0], mAutoCompleteTextView.getText().toString());
 
-        // re-set 'clicked' flag to false
-        listener.clearItemClickedStatus();
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAutoCompleteTextView.showDropDown();
-            }
-        });
+        mInstrumentation.runOnMainSync(mAutoCompleteTextView::showDropDown);
         mInstrumentation.waitForIdleSync();
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
-        assertTrue(listener.isOnItemClicked());
+        verify(mockItemClickListener, times(2)).onItemClick(any(AdapterView.class), any(View.class),
+                eq(0), eq(0L));
         assertEquals(WORDS[0], mAutoCompleteTextView.getText().toString());
         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
 
-        listener.clearItemClickedStatus();
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAutoCompleteTextView.showDropDown();
-            }
-        });
+        mInstrumentation.runOnMainSync(mAutoCompleteTextView::showDropDown);
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
         // Test normal key code.
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
-        assertFalse(listener.isOnItemClicked());
+        verifyNoMoreInteractions(mockItemClickListener);
         assertNotSame("", mAutoCompleteTextView.getText().toString());
         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
 
-        listener.clearItemClickedStatus();
-
         // Test the method on the scene of popup is closed.
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-               mAutoCompleteTextView.dismissDropDown();
-            }
-        });
+        mInstrumentation.runOnMainSync(mAutoCompleteTextView::dismissDropDown);
 
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
-        assertFalse(listener.isOnItemClicked());
+        verifyNoMoreInteractions(mockItemClickListener);
         assertNotSame("", mAutoCompleteTextView.getText().toString());
         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
     }
 
-    @UiThreadTest
+    @Test
+    public void testPerformCompletionExplicit() {
+        final AdapterView.OnItemClickListener mockItemClickListener =
+                mock(AdapterView.OnItemClickListener.class);
+        assertFalse(mAutoCompleteTextView.isPerformingCompletion());
+
+        // Create a custom watcher that checks isPerformingCompletion to return true
+        // in the "middle" of the performCompletion processing. We also spy on this watcher
+        // to make sure that its onTextChanged is invoked.
+        final TextWatcher myTextWatcher = new MyTextWatcher(WORDS[1]);
+        final TextWatcher spyTextWatcher = spy(myTextWatcher);
+        mAutoCompleteTextView.addTextChangedListener(spyTextWatcher);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.requestFocus();
+            mAutoCompleteTextView.showDropDown();
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mAutoCompleteTextView.isPopupShowing());
+        assertFalse(mAutoCompleteTextView.isPerformingCompletion());
+
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        mInstrumentation.runOnMainSync(mAutoCompleteTextView::performCompletion);
+        verify(mockItemClickListener, times(1)).onItemClick(any(AdapterView.class), any(View.class),
+                eq(1), eq(1L));
+        assertEquals(WORDS[1], mAutoCompleteTextView.getText().toString());
+        assertFalse(mAutoCompleteTextView.isPerformingCompletion());
+        assertFalse(mAutoCompleteTextView.isPopupShowing());
+
+        verify(spyTextWatcher, atLeastOnce()).onTextChanged(sameCharSequence(WORDS[1]),
+                eq(0), eq(0), eq(WORDS[1].length()));
+        verifyNoMoreInteractions(mockItemClickListener);
+    }
+
+    @Test
+    public void testSetTextWithCompletion() {
+        final AdapterView.OnItemClickListener mockItemClickListener =
+                mock(AdapterView.OnItemClickListener.class);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+            mAutoCompleteTextView.setAdapter(mAdapter);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(mAutoCompleteTextView.isPopupShowing());
+
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText("testO", true));
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mAutoCompleteTextView.isPopupShowing());
+        verifyZeroInteractions(mockItemClickListener);
+    }
+
+    @Test
+    public void testSetTextWithNoCompletion() {
+        final AdapterView.OnItemClickListener mockItemClickListener =
+                mock(AdapterView.OnItemClickListener.class);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+            mAutoCompleteTextView.setAdapter(mAdapter);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(mAutoCompleteTextView.isPopupShowing());
+
+        mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText("testO", false));
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(mAutoCompleteTextView.isPopupShowing());
+        verifyZeroInteractions(mockItemClickListener);
+    }
+
+    @Test
     public void testPerformValidation() {
         final CharSequence text = "this";
 
-        mAutoCompleteTextView.setValidator(mValidator);
-        mAutoCompleteTextView.setAdapter((ArrayAdapter<String>) null);
-        mAutoCompleteTextView.setText(text);
-        mAutoCompleteTextView.performValidation();
+        mInstrumentation.runOnMainSync(() -> {
+                mAutoCompleteTextView.setValidator(mValidator);
+                mAutoCompleteTextView.setAdapter((ArrayAdapter<String>) null);
+                mAutoCompleteTextView.setText(text);
+                mAutoCompleteTextView.performValidation();
+        });
 
         assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
         mAutoCompleteTextView.setValidator(null);
     }
 
-    public void testSetCompletionHint() {
+    @Test
+    public void testAccessCompletionHint() {
         mAutoCompleteTextView.setCompletionHint("TEST HINT");
+        assertEquals("TEST HINT", mAutoCompleteTextView.getCompletionHint());
+
+        mAutoCompleteTextView.setCompletionHint(null);
+        assertNull(mAutoCompleteTextView.getCompletionHint());
     }
 
-    public void testOnAttachedToWindow() {
-        // implement details, do not test
-    }
+    @Test
+    public void testAccessListSelection() {
+        final AdapterView.OnItemClickListener mockItemClickListener =
+                mock(AdapterView.OnItemClickListener.class);
 
-    public void testOnCommitCompletion() {
-        // implement details, do not test
-    }
-
-    public void testOnDetachedFromWindow() {
-        // implement details, do not test
-    }
-
-    public void testOnKeyPreIme() {
-        // implement details, do not test
-    }
-
-    public void testAccessListSelection() throws Throwable {
-        final MockOnItemClickListener listener = new MockOnItemClickListener();
-
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAutoCompleteTextView.setOnItemClickListener(listener);
+        mInstrumentation.runOnMainSync(() -> {
+                mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
                 mAutoCompleteTextView.setAdapter(mAdapter);
                 mAutoCompleteTextView.requestFocus();
                 mAutoCompleteTextView.showDropDown();
-            }
         });
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mInstrumentation.runOnMainSync(() -> {
                 mAutoCompleteTextView.setListSelection(1);
                 assertEquals(1, mAutoCompleteTextView.getListSelection());
 
@@ -639,11 +773,11 @@
 
                 mAutoCompleteTextView.clearListSelection();
                 assertEquals(2, mAutoCompleteTextView.getListSelection());
-            }
         });
         mInstrumentation.waitForIdleSync();
     }
 
+    @Test
     public void testAccessDropDownAnchor() {
         mAutoCompleteTextView.setDropDownAnchor(View.NO_ID);
         assertEquals(View.NO_ID, mAutoCompleteTextView.getDropDownAnchor());
@@ -652,6 +786,7 @@
         assertEquals(0x5555, mAutoCompleteTextView.getDropDownAnchor());
     }
 
+    @Test
     public void testAccessDropDownWidth() {
         mAutoCompleteTextView.setDropDownWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, mAutoCompleteTextView.getDropDownWidth());
@@ -660,75 +795,25 @@
         assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, mAutoCompleteTextView.getDropDownWidth());
     }
 
-    private static class MockOnItemClickListener implements AdapterView.OnItemClickListener {
-        private boolean mOnItemClickedFlag = false;
-
-        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-            mOnItemClickedFlag = true;
-            return;
-        }
-
-        public boolean isOnItemClicked() {
-            return mOnItemClickedFlag;
-        }
-
-        public void clearItemClickedStatus() {
-            mOnItemClickedFlag = false;
-        }
-    }
-
-    private static class MockOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
-        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-            return;
-        }
-
-        public void onNothingSelected(AdapterView<?> parent) {
-            return;
-        }
-    }
-
     private class MockValidator implements AutoCompleteTextView.Validator {
         public CharSequence fixText(CharSequence invalidText) {
             return STRING_VALIDATED;
         }
 
         public boolean isValid(CharSequence text) {
-            if (text == STRING_TEST) {
-                return true;
-            }
-            return false;
+            return (text == STRING_TEST);
         }
     }
 
-    private static class MockAutoCompleteTextView extends AutoCompleteTextView {
-        private boolean mOnTextChangedFlag = false;
-        private boolean mOnFilterCompleteFlag = false;
-        private String lastChangeText = "";
-        private int mStart = 0;
-        private int mBefore = 0;
-        private int mAfter = 0;
-
-        public void resetStatus() {
-            mOnTextChangedFlag = false;
-            mOnFilterCompleteFlag = false;
-            mStart = 0;
-            mBefore = 0;
-            mAfter = 0;
-        }
-
+    protected static class MockAutoCompleteTextView extends AutoCompleteTextView {
         public MockAutoCompleteTextView(Context context) {
             super(context);
-            resetStatus();
         }
 
         public MockAutoCompleteTextView(Context context, AttributeSet attrs) {
             super(context, attrs);
         }
 
-        protected MockAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) {
-            super(context, attrs, defStyle);
-        }
-
         @Override
         protected CharSequence convertSelectionToString(Object selectedItem) {
             return super.convertSelectionToString(selectedItem);
@@ -745,16 +830,6 @@
         }
 
         @Override
-        protected void onTextChanged(CharSequence text, int start, int before, int after) {
-            super.onTextChanged(text, start, before, after);
-            mOnTextChangedFlag = true;
-            lastChangeText = text.toString();
-            mStart = start;
-            mBefore = before;
-            mAfter = after;
-        }
-
-        @Override
         protected void performFiltering(CharSequence text, int keyCode) {
             super.performFiltering(text, keyCode);
         }
@@ -768,36 +843,6 @@
         protected boolean setFrame(int l, int t, int r, int b) {
             return super.setFrame(l, t, r, b);
         }
-
-        @Override
-        public void onFilterComplete(int count) {
-            super.onFilterComplete(count);
-            mOnFilterCompleteFlag = true;
-        }
-
-        protected boolean isOnTextChanged() {
-            return mOnTextChangedFlag;
-        }
-
-        protected String getLastChangeText() {
-            return lastChangeText;
-        }
-
-        protected boolean isOnFilterComplete() {
-            return mOnFilterCompleteFlag;
-        }
-
-        protected int getStart() {
-            return mStart;
-        }
-
-        protected int getBefore() {
-            return mBefore;
-        }
-
-        protected int getAfter() {
-            return mAfter;
-        }
     }
 
     private static class MockFilter extends Filter {
diff --git a/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java b/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java
index 7659c1e..6b3d34f 100644
--- a/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BaseAdapterTest.java
@@ -16,78 +16,103 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
 import android.database.DataSetObserver;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link BaseAdapter}.
  */
-public class BaseAdapterTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BaseAdapterTest {
+    @Test
     public void testHasStableIds() {
         BaseAdapter baseAdapter = new MockBaseAdapter();
         assertFalse(baseAdapter.hasStableIds());
     }
 
+    @Test
     public void testDataSetObserver() {
         BaseAdapter baseAdapter = new MockBaseAdapter();
-        MockDataSetObserver dataSetObserver = new MockDataSetObserver();
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
 
-        assertFalse(dataSetObserver.hasCalledOnChanged());
+        verifyZeroInteractions(mockDataSetObserver);
         baseAdapter.notifyDataSetChanged();
-        assertFalse(dataSetObserver.hasCalledOnChanged());
+        verifyZeroInteractions(mockDataSetObserver);
 
-        baseAdapter.registerDataSetObserver(dataSetObserver);
+        baseAdapter.registerDataSetObserver(mockDataSetObserver);
         baseAdapter.notifyDataSetChanged();
-        assertTrue(dataSetObserver.hasCalledOnChanged());
+        verify(mockDataSetObserver, times(1)).onChanged();
 
-        dataSetObserver.reset();
-        assertFalse(dataSetObserver.hasCalledOnChanged());
-        baseAdapter.unregisterDataSetObserver(dataSetObserver);
+        reset(mockDataSetObserver);
+        verifyZeroInteractions(mockDataSetObserver);
+        baseAdapter.unregisterDataSetObserver(mockDataSetObserver);
         baseAdapter.notifyDataSetChanged();
-        assertFalse(dataSetObserver.hasCalledOnChanged());
+        verifyZeroInteractions(mockDataSetObserver);
     }
 
+    @Test
     public void testNotifyDataSetInvalidated() {
         BaseAdapter baseAdapter = new MockBaseAdapter();
-        MockDataSetObserver dataSetObserver = new MockDataSetObserver();
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
 
-        assertFalse(dataSetObserver.hasCalledOnInvalidated());
+        verifyZeroInteractions(mockDataSetObserver);
         baseAdapter.notifyDataSetInvalidated();
-        assertFalse(dataSetObserver.hasCalledOnInvalidated());
+        verifyZeroInteractions(mockDataSetObserver);
 
-        baseAdapter.registerDataSetObserver(dataSetObserver);
+        baseAdapter.registerDataSetObserver(mockDataSetObserver);
         baseAdapter.notifyDataSetInvalidated();
-        assertTrue(dataSetObserver.hasCalledOnInvalidated());
+        verify(mockDataSetObserver, times(1)).onInvalidated();
     }
 
+    @Test
     public void testAreAllItemsEnabled() {
         BaseAdapter baseAdapter = new MockBaseAdapter();
         assertTrue(baseAdapter.areAllItemsEnabled());
     }
 
+    @Test
     public void testIsEnabled() {
         BaseAdapter baseAdapter = new MockBaseAdapter();
         assertTrue(baseAdapter.isEnabled(0));
     }
 
+    @Test
     public void testGetDropDownView() {
         BaseAdapter baseAdapter = new MockBaseAdapter();
         assertNull(baseAdapter.getDropDownView(0, null, null));
     }
 
+    @Test
     public void testGetItemViewType() {
         BaseAdapter baseAdapter = new MockBaseAdapter();
         assertEquals(0, baseAdapter.getItemViewType(0));
     }
 
+    @Test
     public void testGetViewTypeCount() {
         BaseAdapter baseAdapter = new MockBaseAdapter();
         assertEquals(1, baseAdapter.getViewTypeCount());
     }
 
+    @Test
     public void testIsEmpty() {
         MockBaseAdapter baseAdapter = new MockBaseAdapter();
 
@@ -121,34 +146,4 @@
             return null;
         }
     }
-
-    private static class MockDataSetObserver extends DataSetObserver {
-        private boolean mCalledOnChanged = false;
-        private boolean mCalledOnInvalidated = false;
-
-        @Override
-        public void onChanged() {
-            super.onChanged();
-            mCalledOnChanged = true;
-        }
-
-        public boolean hasCalledOnChanged() {
-            return mCalledOnChanged;
-        }
-
-        @Override
-        public void onInvalidated() {
-            super.onInvalidated();
-            mCalledOnInvalidated = true;
-        }
-
-        public boolean hasCalledOnInvalidated() {
-            return mCalledOnInvalidated;
-        }
-
-        public void reset() {
-            mCalledOnChanged = false;
-            mCalledOnInvalidated = false;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/BaseExpandableListAdapterTest.java b/tests/tests/widget/src/android/widget/cts/BaseExpandableListAdapterTest.java
index 1737cfd..79a4b91 100644
--- a/tests/tests/widget/src/android/widget/cts/BaseExpandableListAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BaseExpandableListAdapterTest.java
@@ -16,21 +16,37 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
 import android.database.DataSetObserver;
-import android.test.InstrumentationTestCase;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseExpandableListAdapter;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link BaseExpandableListAdapter}.
  */
-public class BaseExpandableListAdapterTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BaseExpandableListAdapterTest {
+    @Test
     public void testAreAllItemsEnabled() {
         MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
         assertTrue(adapter.areAllItemsEnabled());
     }
 
+    @Test
     public void testGetCombinedId() {
         MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
 
@@ -45,6 +61,7 @@
         assertTrue(childID != groupID);
     }
 
+    @Test
     public void testIsEmpty() {
         MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
         assertTrue(adapter.isEmpty());
@@ -52,81 +69,57 @@
         assertFalse(adapter.isEmpty());
     }
 
+    @Test
     public void testNotifyDataSetChanged() {
         MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
-        MockDataSetObserver dataSetObserver = new MockDataSetObserver();
-        adapter.registerDataSetObserver(dataSetObserver);
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        adapter.registerDataSetObserver(mockDataSetObserver);
 
-        assertFalse(dataSetObserver.hasCalledOnChanged());
+        verifyZeroInteractions(mockDataSetObserver);
         adapter.notifyDataSetChanged();
-        assertTrue(dataSetObserver.hasCalledOnChanged());
+        verify(mockDataSetObserver, times(1)).onChanged();
     }
 
+    @Test
     public void testNotifyDataSetInvalidated() {
         MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
-        MockDataSetObserver dataSetObserver = new MockDataSetObserver();
-        adapter.registerDataSetObserver(dataSetObserver);
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        adapter.registerDataSetObserver(mockDataSetObserver);
 
-        assertFalse(dataSetObserver.hasCalledOnInvalidated());
+        verifyZeroInteractions(mockDataSetObserver);
         adapter.notifyDataSetInvalidated();
-        assertTrue(dataSetObserver.hasCalledOnInvalidated());
+        verify(mockDataSetObserver, times(1)).onInvalidated();
     }
 
+    @Test
     public void testOnGroupCollapsed() {
         MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
         // this function is non-operation.
         adapter.onGroupCollapsed(0);
     }
 
+    @Test
     public void testOnGroupExpanded() {
         MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
         // this function is non-operation.
         adapter.onGroupExpanded(0);
     }
 
+    @Test
     public void testDataSetObserver() {
         MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
-        MockDataSetObserver dataSetObserver = new MockDataSetObserver();
-        adapter.registerDataSetObserver(dataSetObserver);
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        adapter.registerDataSetObserver(mockDataSetObserver);
 
-        assertFalse(dataSetObserver.hasCalledOnChanged());
+        verifyZeroInteractions(mockDataSetObserver);
         adapter.notifyDataSetChanged();
-        assertTrue(dataSetObserver.hasCalledOnChanged());
+        verify(mockDataSetObserver, times(1)).onChanged();
 
-        dataSetObserver.reset();
-        assertFalse(dataSetObserver.hasCalledOnChanged());
-        adapter.unregisterDataSetObserver(dataSetObserver);
+        reset(mockDataSetObserver);
+        verifyZeroInteractions(mockDataSetObserver);
+        adapter.unregisterDataSetObserver(mockDataSetObserver);
         adapter.notifyDataSetChanged();
-        assertFalse(dataSetObserver.hasCalledOnChanged());
-    }
-
-    private class MockDataSetObserver extends DataSetObserver {
-        private boolean mCalledOnChanged = false;
-        private boolean mCalledOnInvalidated = false;
-
-        @Override
-        public void onChanged() {
-            super.onChanged();
-            mCalledOnChanged = true;
-        }
-
-        public boolean hasCalledOnChanged() {
-            return mCalledOnChanged;
-        }
-
-        @Override
-        public void onInvalidated() {
-            super.onInvalidated();
-            mCalledOnInvalidated = true;
-        }
-
-        public boolean hasCalledOnInvalidated() {
-            return mCalledOnInvalidated;
-        }
-
-        public void reset() {
-            mCalledOnChanged = false;
-        }
+        verifyZeroInteractions(mockDataSetObserver);
     }
 
     private class MockBaseExpandableListAdapter extends BaseExpandableListAdapter {
diff --git a/tests/tests/widget/src/android/widget/cts/ButtonTest.java b/tests/tests/widget/src/android/widget/cts/ButtonTest.java
index 9da2ecf..9a76c0f 100644
--- a/tests/tests/widget/src/android/widget/cts/ButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ButtonTest.java
@@ -16,45 +16,44 @@
 
 package android.widget.cts;
 
-import org.xmlpull.v1.XmlPullParser;
-
 import android.content.Context;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.widget.Button;
 
-import android.widget.cts.R;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
-
-public class ButtonTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ButtonTest {
+    @Test
     public void testConstructor() {
-        XmlPullParser parser = mContext.getResources().getXml(R.layout.togglebutton_layout);
+        Context context = InstrumentationRegistry.getTargetContext();
+        XmlPullParser parser = context.getResources().getXml(R.layout.togglebutton_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
 
-        new Button(mContext, attrs, 0);
-        new Button(mContext, attrs);
-        new Button(mContext);
+        new Button(context, attrs, 0);
+        new Button(context, attrs);
+        new Button(context);
+    }
 
-        try {
-            new Button(null, null, -1);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new Button(null);
+    }
 
-        try {
-            new Button(null, null);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new Button(null, null);
+    }
 
-        try {
-            new Button(null);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new Button(null, null, -1);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/CalendarViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/CalendarViewCtsActivity.java
index b0a15bf..99101fe 100644
--- a/tests/tests/widget/src/android/widget/cts/CalendarViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/CalendarViewCtsActivity.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.CalendarView;
-import android.widget.Toolbar;
 
 /**
  * A minimal application for {@link CalendarView} test.
diff --git a/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java b/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
index 31ad341..13031d9 100644
--- a/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
@@ -16,41 +16,65 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
 import android.annotation.ColorInt;
 import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase2;
+import android.cts.util.CtsTouchUtils;
+import android.graphics.Rect;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.view.ViewGroup;
 import android.widget.CalendarView;
+import android.widget.ScrollView;
 import android.widget.cts.util.TestUtils;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 
 @MediumTest
-public class CalendarViewTest extends ActivityInstrumentationTestCase2<CalendarViewCtsActivity> {
+@RunWith(AndroidJUnit4.class)
+public class CalendarViewTest {
+    private Instrumentation mInstrumentation;
     private CalendarViewCtsActivity mActivity;
     private CalendarView mCalendarViewMaterial;
     private CalendarView mCalendarViewHolo;
 
-    public CalendarViewTest() {
-        super("android.widget.cts", CalendarViewCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<CalendarViewCtsActivity> mActivityRule
+            = new ActivityTestRule<>(CalendarViewCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         mCalendarViewMaterial = (CalendarView) mActivity.findViewById(R.id.calendar_view_material);
         mCalendarViewHolo = (CalendarView) mActivity.findViewById(R.id.calendar_view_holoyolo);
 
         // Initialize both calendar views to the current date
         final long currentDate = new GregorianCalendar().getTime().getTime();
-        getInstrumentation().runOnMainSync(() -> {
+        mInstrumentation.runOnMainSync(() -> {
             mCalendarViewMaterial.setDate(currentDate);
             mCalendarViewHolo.setDate(currentDate);
         });
     }
 
+    @Test
     public void testConstructor() {
         new CalendarView(mActivity);
 
@@ -58,18 +82,24 @@
 
         new CalendarView(mActivity, null, android.R.attr.calendarViewStyle);
 
+        new CalendarView(mActivity, null, 0, android.R.style.Widget_DeviceDefault_CalendarView);
+
+        new CalendarView(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_CalendarView);
+
+        new CalendarView(mActivity, null, 0, android.R.style.Widget_Material_CalendarView);
+
         new CalendarView(mActivity, null, 0, android.R.style.Widget_Material_Light_CalendarView);
     }
 
+    @Test
     public void testAccessDate() {
-        final Instrumentation instrumentation = getInstrumentation();
-
         // Go back one year
         final Calendar newCalendar = new GregorianCalendar();
         newCalendar.set(Calendar.YEAR, newCalendar.get(Calendar.YEAR) - 1);
         final long yearAgoDate = newCalendar.getTime().getTime();
 
-        instrumentation.runOnMainSync(
+        mInstrumentation.runOnMainSync(
                 () -> mCalendarViewMaterial.setDate(yearAgoDate));
         assertEquals(yearAgoDate, mCalendarViewMaterial.getDate());
 
@@ -77,14 +107,13 @@
         newCalendar.set(Calendar.YEAR, newCalendar.get(Calendar.YEAR) + 2);
         final long yearHenceDate = newCalendar.getTime().getTime();
 
-        instrumentation.runOnMainSync(
+        mInstrumentation.runOnMainSync(
                 () -> mCalendarViewMaterial.setDate(yearHenceDate, true, false));
         assertEquals(yearHenceDate, mCalendarViewMaterial.getDate());
     }
 
+    @Test
     public void testAccessMinMaxDate() {
-        final Instrumentation instrumentation = getInstrumentation();
-
         // Use a range of minus/plus one year as min/max dates
         final Calendar minCalendar = new GregorianCalendar();
         minCalendar.set(Calendar.YEAR, minCalendar.get(Calendar.YEAR) - 1);
@@ -94,7 +123,7 @@
         final long minDate = minCalendar.getTime().getTime();
         final long maxDate = maxCalendar.getTime().getTime();
 
-        instrumentation.runOnMainSync(() -> {
+        mInstrumentation.runOnMainSync(() -> {
             mCalendarViewMaterial.setMinDate(minDate);
             mCalendarViewMaterial.setMaxDate(maxDate);
         });
@@ -103,6 +132,97 @@
         assertEquals(mCalendarViewMaterial.getMaxDate(), maxDate);
     }
 
+    @Test
+    public void testCalendarViewMinMaxRangeRestrictions() {
+        verifyMinMaxRangeRestrictions(mCalendarViewHolo);
+        verifyMinMaxRangeRestrictions(mCalendarViewMaterial);
+    }
+
+    private void verifyMinMaxRangeRestrictions(CalendarView calendarView) {
+        // Use a range of minus/plus one year as min/max dates.
+        final Calendar minCalendar = new GregorianCalendar();
+        minCalendar.set(Calendar.YEAR, minCalendar.get(Calendar.YEAR) - 1);
+        final Calendar maxCalendar = new GregorianCalendar();
+        maxCalendar.set(Calendar.YEAR, maxCalendar.get(Calendar.YEAR) + 1);
+        final long minDate = minCalendar.getTime().getTime();
+        final long maxDate = maxCalendar.getTime().getTime();
+
+        mInstrumentation.runOnMainSync(() -> {
+            calendarView.setMinDate(minDate);
+            calendarView.setMaxDate(maxDate);
+
+            try {
+                calendarView.setDate(minDate - 1);
+                fail("Should throw IllegalArgumentException, date is before minDate");
+            } catch (IllegalArgumentException e) {
+            }
+
+            try {
+                calendarView.setDate(maxDate + 1);
+                fail("Should throw IllegalArgumentException, date is after maxDate");
+            } catch (IllegalArgumentException e) {
+            }
+        });
+    }
+
+    private void verifyOnDateChangeListener(CalendarView calendarView,
+            boolean onlyAllowOneChangeEvent) {
+        final CalendarView.OnDateChangeListener mockDateChangeListener =
+                mock(CalendarView.OnDateChangeListener.class);
+        calendarView.setOnDateChangeListener(mockDateChangeListener);
+
+        // Go back to September 2008
+        final Calendar calendar = new GregorianCalendar();
+        calendar.set(Calendar.YEAR, 2008);
+        calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);
+        calendar.set(Calendar.DAY_OF_MONTH, 16);
+        mInstrumentation.runOnMainSync(
+                () -> calendarView.setDate(calendar.getTime().getTime(), false, true));
+        mInstrumentation.waitForIdleSync();
+
+        // Get bounds of 09/23/2008
+        calendar.set(Calendar.DAY_OF_MONTH, 23);
+        final Rect dayBounds = new Rect();
+        final boolean getDayBoundsSuccess = calendarView.getBoundsForDate(
+                calendar.getTime().getTime(), dayBounds);
+        assertTrue(getDayBoundsSuccess);
+
+        if (onlyAllowOneChangeEvent) {
+            verifyZeroInteractions(mockDateChangeListener);
+        }
+
+        // Use instrumentation to emulate a tap on 09/23/2008
+        CtsTouchUtils.emulateTapOnScreen(mInstrumentation, calendarView,
+                dayBounds.left + dayBounds.width() / 2,
+                dayBounds.top + dayBounds.height() / 2);
+
+        verify(mockDateChangeListener, times(1)).onSelectedDayChange(calendarView,
+                2008, Calendar.SEPTEMBER, 23);
+        if (onlyAllowOneChangeEvent) {
+            verifyNoMoreInteractions(mockDateChangeListener);
+        }
+    }
+
+    @Test
+    public void testOnDateChangeListenerHolo() {
+        // Scroll the Holo calendar view all the way up so it's fully visible
+        final ScrollView scroller = (ScrollView) mActivity.findViewById(R.id.scroller);
+        final ViewGroup container = (ViewGroup) scroller.findViewById(R.id.container);
+
+        mInstrumentation.runOnMainSync(() -> scroller.scrollTo(0, container.getHeight()));
+        // Note that in pre-Material world we are "allowing" the CalendarView to notify
+        // the date change listener on multiple occasions. This is the old behavior of the widget.
+        verifyOnDateChangeListener(mCalendarViewHolo, false);
+    }
+
+    @Test
+    public void testOnDateChangeListenerMaterial() {
+        // Note that in Material world only "real" date change events are allowed to be reported
+        // to our listener. This is the new behavior of the widget.
+        verifyOnDateChangeListener(mCalendarViewMaterial, true);
+    }
+
+    @Test
     public void testAppearanceMaterial() {
         // The logic in this method is performed on a Material-styled CalendarView and
         // non-deprecated attributes / visual appearance APIs
@@ -114,22 +234,21 @@
         assertEquals(R.style.TextAppearance_WithColorGreen,
                 mCalendarViewMaterial.getWeekDayTextAppearance());
 
-        final Instrumentation instrumentation = getInstrumentation();
-
         // Change the visual appearance of the widget
-        instrumentation.runOnMainSync(() -> {
-            mCalendarViewMaterial.setFirstDayOfWeek(3);
+        mInstrumentation.runOnMainSync(() -> {
+            mCalendarViewMaterial.setFirstDayOfWeek(Calendar.TUESDAY);
             mCalendarViewMaterial.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
             mCalendarViewMaterial.setWeekDayTextAppearance(R.style.TextAppearance_WithColorMagenta);
         });
 
-        assertEquals(3, mCalendarViewMaterial.getFirstDayOfWeek());
+        assertEquals(Calendar.TUESDAY, mCalendarViewMaterial.getFirstDayOfWeek());
         assertEquals(R.style.TextAppearance_WithColorBlue,
                 mCalendarViewMaterial.getDateTextAppearance());
         assertEquals(R.style.TextAppearance_WithColorMagenta,
                 mCalendarViewMaterial.getWeekDayTextAppearance());
     }
 
+    @Test
     public void testAppearanceHolo() {
         // All the logic in this method is performed on a Holo-styled CalendarView, as
         // under Material design we are ignoring most of these decorative attributes
@@ -151,8 +270,6 @@
         TestUtils.assertAllPixelsOfColor("Selected date vertical bar blue",
                 mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFF0000FF, 1, true);
 
-        final Instrumentation instrumentation = getInstrumentation();
-
         // Change the visual appearance of the widget
         final @ColorInt int newSelectedWeekBackgroundColor =
                 mActivity.getColor(R.color.calendarview_week_background_new);
@@ -165,8 +282,8 @@
         final @ColorInt int newWeekSeparatorLineColor =
                 mActivity.getColor(R.color.calendarview_week_separatorline_new);
 
-        instrumentation.runOnMainSync(() -> {
-            mCalendarViewHolo.setFirstDayOfWeek(1);
+        mInstrumentation.runOnMainSync(() -> {
+            mCalendarViewHolo.setFirstDayOfWeek(Calendar.SUNDAY);
             mCalendarViewHolo.setShownWeekCount(4);
             mCalendarViewHolo.setShowWeekNumber(true);
             mCalendarViewHolo.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
@@ -178,7 +295,7 @@
             mCalendarViewHolo.setWeekSeparatorLineColor(newWeekSeparatorLineColor);
         });
 
-        assertEquals(1, mCalendarViewHolo.getFirstDayOfWeek());
+        assertEquals(Calendar.SUNDAY, mCalendarViewHolo.getFirstDayOfWeek());
         assertEquals(4, mCalendarViewHolo.getShownWeekCount());
         assertTrue(mCalendarViewHolo.getShowWeekNumber());
         assertEquals(R.style.TextAppearance_WithColorBlue,
@@ -196,12 +313,12 @@
         assertEquals(newWeekSeparatorLineColor,
                 mCalendarViewHolo.getWeekSeparatorLineColor());
 
-        instrumentation.runOnMainSync(
+        mInstrumentation.runOnMainSync(
                 () -> mCalendarViewHolo.setSelectedDateVerticalBar(R.drawable.yellow_fill));
         TestUtils.assertAllPixelsOfColor("Selected date vertical bar yellow",
                 mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFFFFFF00, 1, true);
 
-        instrumentation.runOnMainSync(
+        mInstrumentation.runOnMainSync(
                 () -> mCalendarViewHolo.setSelectedDateVerticalBar(
                         mActivity.getDrawable(R.drawable.magenta_fill)));
         TestUtils.assertAllPixelsOfColor("Selected date vertical bar magenta",
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/CheckBoxCtsActivity.java
similarity index 68%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/CheckBoxCtsActivity.java
index 481f5be..9ad0b23 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckBoxCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.CheckBox;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link CheckBox} test.
+ */
+public class CheckBoxCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.checkbox_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java b/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
index b3a6e67..ed2ab64 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
@@ -16,44 +16,184 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
-import android.util.Xml;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.cts.util.CtsTouchUtils;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
 import android.widget.CheckBox;
 
-public class CheckBoxTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CheckBoxTest {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private CheckBox mCheckBox;
+
+    @Rule
+    public ActivityTestRule<CheckBoxCtsActivity> mActivityRule
+            = new ActivityTestRule<>(CheckBoxCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mCheckBox = (CheckBox) mActivity.findViewById(R.id.check_box);
+    }
+
+    @Test
     public void testConstructor() {
-        XmlPullParser parser = mContext.getResources().getXml(R.layout.checkbox_layout);
-        AttributeSet mAttrSet = Xml.asAttributeSet(parser);
+        new CheckBox(mActivity);
+        new CheckBox(mActivity, null);
+        new CheckBox(mActivity, null, android.R.attr.checkboxStyle);
+        new CheckBox(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_CompoundButton_CheckBox);
+        new CheckBox(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_CompoundButton_CheckBox);
+        new CheckBox(mActivity, null, 0,
+                android.R.style.Widget_Material_CompoundButton_CheckBox);
+        new CheckBox(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_CompoundButton_CheckBox);
+    }
 
-        new CheckBox(mContext, mAttrSet, 0);
-        new CheckBox(mContext, mAttrSet);
-        new CheckBox(mContext);
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new CheckBox(null);
+    }
 
-        try {
-            new CheckBox(null, null, -1);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new CheckBox(null, null);
+    }
 
-        try {
-            new CheckBox(null, null);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new CheckBox(null, null, -1);
+    }
 
-        try {
-            new CheckBox(null);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+    @Test
+    public void testText() {
+        assertTrue(TextUtils.equals(
+                mActivity.getString(R.string.hello_world), mCheckBox.getText()));
+
+        mInstrumentation.runOnMainSync(() -> mCheckBox.setText("new text"));
+        assertTrue(TextUtils.equals("new text", mCheckBox.getText()));
+
+        mInstrumentation.runOnMainSync(() -> mCheckBox.setText(R.string.text_name));
+        assertTrue(TextUtils.equals(mActivity.getString(R.string.text_name), mCheckBox.getText()));
+    }
+
+    @Test
+    public void testAccessChecked() {
+        final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CheckBox.OnCheckedChangeListener.class);
+        mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mCheckBox.isChecked());
+
+        // not checked -> not checked
+        mInstrumentation.runOnMainSync(() -> mCheckBox.setChecked(false));
+        verifyZeroInteractions(mockCheckedChangeListener);
+        assertFalse(mCheckBox.isChecked());
+
+        // not checked -> checked
+        mInstrumentation.runOnMainSync(() -> mCheckBox.setChecked(true));
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+        assertTrue(mCheckBox.isChecked());
+
+        // checked -> checked
+        mInstrumentation.runOnMainSync(() -> mCheckBox.setChecked(true));
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+        assertTrue(mCheckBox.isChecked());
+
+        // checked -> not checked
+        mInstrumentation.runOnMainSync(() -> mCheckBox.setChecked(false));
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, false);
+        assertFalse(mCheckBox.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
+    }
+
+    @Test
+    public void testToggleViaApi() {
+        final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CheckBox.OnCheckedChangeListener.class);
+        mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mCheckBox.isChecked());
+
+        // toggle to checked
+        mInstrumentation.runOnMainSync(mCheckBox::toggle);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+        assertTrue(mCheckBox.isChecked());
+
+        // toggle to not checked
+        mInstrumentation.runOnMainSync(mCheckBox::toggle);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, false);
+        assertFalse(mCheckBox.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
+    }
+
+    @Test
+    public void testToggleViaEmulatedTap() {
+        final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CheckBox.OnCheckedChangeListener.class);
+        mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mCheckBox.isChecked());
+
+        // tap to checked
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mCheckBox);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+        assertTrue(mCheckBox.isChecked());
+
+        // tap to not checked
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mCheckBox);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, false);
+        assertFalse(mCheckBox.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
+    }
+
+    @Test
+    public void testToggleViaPerformClick() {
+        final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CheckBox.OnCheckedChangeListener.class);
+        mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mCheckBox.isChecked());
+
+        // click to checked
+        mInstrumentation.runOnMainSync(mCheckBox::performClick);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+        assertTrue(mCheckBox.isChecked());
+
+        // click to not checked
+        mInstrumentation.runOnMainSync(mCheckBox::performClick);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, false);
+        assertFalse(mCheckBox.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
index 52bef54..066697a 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
@@ -16,13 +16,12 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.CheckedTextView;
 
 /**
- * A minimal application for CheckedTextView test.
+ * A minimal application for {@link CheckedTextView} test.
  */
 public class CheckedTextViewCtsActivity extends Activity {
     /**
diff --git a/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java b/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
index 039ca70..d564df3 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
@@ -16,17 +16,25 @@
 
 package android.widget.cts;
 
-import android.os.Parcelable;
-import android.widget.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.content.res.Resources;
+import android.content.res.ColorStateList;
+import android.cts.util.WidgetTestUtils;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
-import android.test.ActivityInstrumentationTestCase2;
+import android.os.Parcelable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.StateSet;
 import android.view.View;
@@ -35,84 +43,91 @@
 import android.widget.CheckedTextView;
 import android.widget.ListAdapter;
 import android.widget.ListView;
+import android.widget.cts.util.TestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.Arrays;
 
-public class CheckedTextViewTest extends
-        ActivityInstrumentationTestCase2<CheckedTextViewCtsActivity> {
-    private Resources mResources;
-    private Activity mActivity;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CheckedTextViewTest {
     private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private ListView mListView;
+    private CheckedTextView mCheckedTextView;
+    private Parcelable mState;
 
-    public CheckedTextViewTest() {
-        super("android.widget.cts", CheckedTextViewCtsActivity.class);
+    @Rule
+    public ActivityTestRule<CheckedTextViewCtsActivity> mActivityRule
+            = new ActivityTestRule<>(CheckedTextViewCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mListView = (ListView) mActivity.findViewById(R.id.checkedtextview_listview);
+        mCheckedTextView = (CheckedTextView) mActivity.findViewById(R.id.checkedtextview_test);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mResources = mActivity.getResources();
-    }
-
+    @Test
     public void testConstructor() {
-        new MockCheckedTextView(mActivity, null, 0);
-        new MockCheckedTextView(mActivity, null);
-        new MockCheckedTextView(mActivity);
-
-        try {
-            new MockCheckedTextView(null, null, -1);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new MockCheckedTextView(null, null);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new MockCheckedTextView(null);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        new CheckedTextView(mActivity);
+        new CheckedTextView(mActivity, null);
+        new CheckedTextView(mActivity, null, android.R.attr.checkedTextViewStyle);
+        new CheckedTextView(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_CheckedTextView);
+        new CheckedTextView(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_CheckedTextView);
+        new CheckedTextView(mActivity, null, 0,
+                android.R.style.Widget_Material_CheckedTextView);
+        new CheckedTextView(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_CheckedTextView);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new CheckedTextView(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new CheckedTextView(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new CheckedTextView(null, null, -1);
+    }
+
+    @Test
     public void testChecked() {
-        final ListView lv = (ListView) mActivity.findViewById(R.id.checkedtextview_listview);
+        mInstrumentation.runOnMainSync(() -> {
+            mListView.setAdapter(new CheckedTextViewAdapter());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                lv.setAdapter(new CheckedTextViewAdapter());
-
-                lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-                lv.setItemChecked(1, true);
-            }
+            mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+            mListView.setItemChecked(1, true);
         });
         mInstrumentation.waitForIdleSync();
 
-        assertEquals(1, lv.getCheckedItemPosition());
-        assertTrue(lv.isItemChecked(1));
-        assertFalse(lv.isItemChecked(0));
+        assertEquals(1, mListView.getCheckedItemPosition());
+        assertTrue(mListView.isItemChecked(1));
+        assertFalse(mListView.isItemChecked(0));
 
-        ListAdapter adapter = lv.getAdapter();
-        CheckedTextView view0 = (CheckedTextView) adapter.getView(0, null, null);
-        CheckedTextView view1 = (CheckedTextView) adapter.getView(1, null, null);
-        CheckedTextView view2 = (CheckedTextView) adapter.getView(2, null, null);
+        final ListAdapter adapter = mListView.getAdapter();
+        final CheckedTextView view0 = (CheckedTextView) adapter.getView(0, null, null);
+        final CheckedTextView view1 = (CheckedTextView) adapter.getView(1, null, null);
+        final CheckedTextView view2 = (CheckedTextView) adapter.getView(2, null, null);
         assertFalse(view0.isChecked());
         assertTrue(view1.isChecked());
         assertFalse(view2.isChecked());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
-                lv.setItemChecked(2, true);
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+            mListView.setItemChecked(2, true);
         });
         mInstrumentation.waitForIdleSync();
         assertFalse(view0.isChecked());
@@ -127,185 +142,228 @@
         assertFalse(view2.isChecked());
     }
 
+    @Test
     public void testToggle() {
-        CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
-        assertFalse(checkedTextView.isChecked());
+        assertFalse(mCheckedTextView.isChecked());
 
-        checkedTextView.toggle();
-        assertTrue(checkedTextView.isChecked());
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.toggle());
+        assertTrue(mCheckedTextView.isChecked());
 
-        checkedTextView.toggle();
-        assertFalse(checkedTextView.isChecked());
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.toggle());
+        assertFalse(mCheckedTextView.isChecked());
 
-        checkedTextView.setChecked(true);
-        checkedTextView.toggle();
-        assertFalse(checkedTextView.isChecked());
+        mInstrumentation.runOnMainSync(() -> {
+            mCheckedTextView.setChecked(true);
+            mCheckedTextView.toggle();
+        });
+        assertFalse(mCheckedTextView.isChecked());
     }
 
+    @Test
     public void testDrawableStateChanged() {
         MockCheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
 
-        checkedTextView.reset();
         assertFalse(checkedTextView.hasDrawableStateChanged());
         checkedTextView.refreshDrawableState();
         assertTrue(checkedTextView.hasDrawableStateChanged());
     }
 
+    @Test
     public void testSetPadding() {
-        final CheckedTextView lv
-                = (CheckedTextView) mActivity.findViewById(R.id.checkedtextview_test);
-        assertNotNull(lv);
-
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                lv.setPadding(1, 2, 3, 4);
-                lv.requestLayout();
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            mListView.setPadding(1, 2, 3, 4);
+            mListView.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
-        int origTop = lv.getPaddingTop();
-        int origBottom = lv.getPaddingBottom();
-        int origLeft = lv.getPaddingLeft();
-        int origRight = lv.getPaddingRight();
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                lv.setPadding(10, 20, 30, 40);
-                lv.requestLayout();
-            }
+        final int origTop = mListView.getPaddingTop();
+        final int origBottom = mListView.getPaddingBottom();
+        final int origLeft = mListView.getPaddingLeft();
+        final int origRight = mListView.getPaddingRight();
+
+        mInstrumentation.runOnMainSync(() -> {
+            mListView.setPadding(10, 20, 30, 40);
+            mListView.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
-        assertTrue(origTop < lv.getPaddingTop());
-        assertTrue(origBottom < lv.getPaddingBottom());
-        assertTrue(origLeft < lv.getPaddingLeft());
-        assertTrue(origRight < lv.getPaddingRight());
+
+        assertTrue(origTop < mListView.getPaddingTop());
+        assertTrue(origBottom < mListView.getPaddingBottom());
+        assertTrue(origLeft < mListView.getPaddingLeft());
+        assertTrue(origRight < mListView.getPaddingRight());
     }
 
     private void cleanUpForceLayoutFlags(View view) {
         if (view != null) {
-            view.layout(0, 0, 0, 0);
+            mInstrumentation.runOnMainSync(() -> view.layout(0, 0, 0, 0));
             assertFalse(view.isLayoutRequested());
         }
     }
 
+    @Test
     public void testSetCheckMarkDrawableByDrawable() {
-        CheckedTextView checkedTextView;
         int basePaddingRight = 10;
 
         // set drawable when checkedTextView is GONE
-        checkedTextView = new MockCheckedTextView(mActivity);
-        checkedTextView.setVisibility(View.GONE);
-        Drawable firstDrawable = mResources.getDrawable(R.drawable.scenery);
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setVisibility(View.GONE));
+        final Drawable firstDrawable = mActivity.getDrawable(R.drawable.scenery);
         firstDrawable.setVisible(true, false);
         assertEquals(StateSet.WILD_CARD, firstDrawable.getState());
-        cleanUpForceLayoutFlags(checkedTextView);
+        cleanUpForceLayoutFlags(mCheckedTextView);
 
-        checkedTextView.setCheckMarkDrawable(firstDrawable);
-        assertEquals(firstDrawable.getIntrinsicWidth(), checkedTextView.getPaddingRight());
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(firstDrawable));
+        assertEquals(firstDrawable.getIntrinsicWidth(), mCheckedTextView.getPaddingRight());
         assertFalse(firstDrawable.isVisible());
-        assertTrue(Arrays.equals(checkedTextView.getDrawableState(), firstDrawable.getState()));
-        assertTrue(checkedTextView.isLayoutRequested());
+        assertTrue(Arrays.equals(mCheckedTextView.getDrawableState(), firstDrawable.getState()));
+        assertTrue(mCheckedTextView.isLayoutRequested());
+
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(null));
 
         // update drawable when checkedTextView is VISIBLE
-        checkedTextView = new MockCheckedTextView(mActivity);
-        checkedTextView.setVisibility(View.VISIBLE);
-        checkedTextView.setPadding(0, 0, basePaddingRight, 0);
-        Drawable secondDrawable = mResources.getDrawable(R.drawable.pass);
+        mInstrumentation.runOnMainSync(() -> {
+            mCheckedTextView.setVisibility(View.VISIBLE);
+            mCheckedTextView.setPadding(0, 0, basePaddingRight, 0);
+        });
+        final Drawable secondDrawable = mActivity.getDrawable(R.drawable.pass);
         secondDrawable.setVisible(true, false);
         assertEquals(StateSet.WILD_CARD, secondDrawable.getState());
-        cleanUpForceLayoutFlags(checkedTextView);
+        cleanUpForceLayoutFlags(mCheckedTextView);
 
-        checkedTextView.setCheckMarkDrawable(secondDrawable);
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(secondDrawable));
         assertEquals(secondDrawable.getIntrinsicWidth() + basePaddingRight,
-                checkedTextView.getPaddingRight());
+                mCheckedTextView.getPaddingRight());
         assertTrue(secondDrawable.isVisible());
-        assertTrue(Arrays.equals(checkedTextView.getDrawableState(), secondDrawable.getState()));
-        assertTrue(checkedTextView.isLayoutRequested());
+        assertTrue(Arrays.equals(mCheckedTextView.getDrawableState(), secondDrawable.getState()));
+        assertTrue(mCheckedTextView.isLayoutRequested());
 
-        cleanUpForceLayoutFlags(checkedTextView);
-        checkedTextView.setCheckMarkDrawable(null);
-        assertEquals(basePaddingRight, checkedTextView.getPaddingRight());
-        assertTrue(checkedTextView.isLayoutRequested());
+        cleanUpForceLayoutFlags(mCheckedTextView);
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(null));
+        assertEquals(basePaddingRight, mCheckedTextView.getPaddingRight());
+        assertTrue(mCheckedTextView.isLayoutRequested());
     }
 
+    @Test
     public void testSetCheckMarkDrawableById() {
-        CheckedTextView checkedTextView;
         int basePaddingRight = 10;
 
         // set drawable
-        checkedTextView = new MockCheckedTextView(mActivity);
-        checkedTextView.setPadding(0, 0, basePaddingRight, 0);
-        Drawable firstDrawable = mResources.getDrawable(R.drawable.scenery);
-        cleanUpForceLayoutFlags(checkedTextView);
+        mInstrumentation.runOnMainSync(
+                () -> mCheckedTextView.setPadding(0, 0, basePaddingRight, 0));
+        Drawable firstDrawable = mActivity.getDrawable(R.drawable.scenery);
+        cleanUpForceLayoutFlags(mCheckedTextView);
 
-        checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
+        mInstrumentation.runOnMainSync(
+                () -> mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery));
         assertEquals(firstDrawable.getIntrinsicWidth() + basePaddingRight,
-                checkedTextView.getPaddingRight());
-        assertTrue(checkedTextView.isLayoutRequested());
+                mCheckedTextView.getPaddingRight());
+        assertTrue(mCheckedTextView.isLayoutRequested());
 
         // set the same drawable again
-        cleanUpForceLayoutFlags(checkedTextView);
-        checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
+        cleanUpForceLayoutFlags(mCheckedTextView);
+        mInstrumentation.runOnMainSync(
+                () -> mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery));
         assertEquals(firstDrawable.getIntrinsicWidth() + basePaddingRight,
-                checkedTextView.getPaddingRight());
-        assertFalse(checkedTextView.isLayoutRequested());
+                mCheckedTextView.getPaddingRight());
+        assertFalse(mCheckedTextView.isLayoutRequested());
 
         // update drawable
-        Drawable secondDrawable = mResources.getDrawable(R.drawable.pass);
-        checkedTextView.setCheckMarkDrawable(secondDrawable);
+        final Drawable secondDrawable = mActivity.getDrawable(R.drawable.pass);
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(secondDrawable));
         assertEquals(secondDrawable.getIntrinsicWidth() + basePaddingRight,
-                checkedTextView.getPaddingRight());
-        assertTrue(checkedTextView.isLayoutRequested());
+                mCheckedTextView.getPaddingRight());
+        assertTrue(mCheckedTextView.isLayoutRequested());
+
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(null));
 
         // resId is 0
-        checkedTextView = new MockCheckedTextView(mActivity);
-        checkedTextView.setPadding(0, 0, basePaddingRight, 0);
-        cleanUpForceLayoutFlags(checkedTextView);
+        mInstrumentation.runOnMainSync(
+                () -> mCheckedTextView.setPadding(0, 0, basePaddingRight, 0));
+        cleanUpForceLayoutFlags(mCheckedTextView);
 
-        checkedTextView.setCheckMarkDrawable(0);
-        assertEquals(basePaddingRight, checkedTextView.getPaddingRight());
-        assertFalse(checkedTextView.isLayoutRequested());
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(0));
+        assertEquals(basePaddingRight, mCheckedTextView.getPaddingRight());
+        assertFalse(mCheckedTextView.isLayoutRequested());
     }
 
+    @Test
     public void testSetCheckMarkByMixedTypes() {
-        CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
-        cleanUpForceLayoutFlags(checkedTextView);
+        cleanUpForceLayoutFlags(mCheckedTextView);
 
         // Specifically test for b/22626247 (AOSP issue 180455).
-        checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
-        checkedTextView.setCheckMarkDrawable(null);
-        checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
-        assertNotNull(checkedTextView.getCheckMarkDrawable());
+        mInstrumentation.runOnMainSync(() -> {
+            mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery);
+            mCheckedTextView.setCheckMarkDrawable(null);
+            mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery);
+        });
+        assertNotNull(mCheckedTextView.getCheckMarkDrawable());
     }
 
+    @Test
     public void testAccessInstanceState() {
-        CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
-        Parcelable state;
+        assertFalse(mCheckedTextView.isChecked());
+        assertFalse(mCheckedTextView.getFreezesText());
 
-        assertFalse(checkedTextView.isChecked());
-        assertFalse(checkedTextView.getFreezesText());
+        mInstrumentation.runOnMainSync(() -> mState = mCheckedTextView.onSaveInstanceState());
+        assertNotNull(mState);
+        assertFalse(mCheckedTextView.getFreezesText());
 
-        state = checkedTextView.onSaveInstanceState();
-        assertNotNull(state);
-        assertFalse(checkedTextView.getFreezesText());
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setChecked(true));
 
-        checkedTextView.setChecked(true);
-
-        checkedTextView.onRestoreInstanceState(state);
-        assertFalse(checkedTextView.isChecked());
-        assertTrue(checkedTextView.isLayoutRequested());
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.onRestoreInstanceState(mState));
+        assertFalse(mCheckedTextView.isChecked());
+        assertTrue(mCheckedTextView.isLayoutRequested());
     }
 
-    public void testOnDraw() {
-        // Do not test. Implementation details.
-    }
+    @Test
+    public void testCheckMarkTinting() {
+        mInstrumentation.runOnMainSync(() -> mCheckedTextView.setChecked(true));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mCheckedTextView,
+                () -> mCheckedTextView.setCheckMarkDrawable(R.drawable.icon_red));
 
-    public void testOnCreateDrawableState() {
-        // Do not test. Implementation details.
+        Drawable checkMark = mCheckedTextView.getCheckMarkDrawable();
+        TestUtils.assertAllPixelsOfColor("Initial state is red", checkMark,
+                checkMark.getBounds().width(), checkMark.getBounds().height(), false,
+                Color.RED, 1, true);
+
+        // With SRC_IN we're expecting the translucent tint color to "take over" the
+        // original red checkmark.
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mCheckedTextView, () -> {
+            mCheckedTextView.setCheckMarkTintMode(PorterDuff.Mode.SRC_IN);
+            mCheckedTextView.setCheckMarkTintList(ColorStateList.valueOf(0x8000FF00));
+        });
+
+        assertEquals(PorterDuff.Mode.SRC_IN, mCheckedTextView.getCheckMarkTintMode());
+        assertEquals(0x8000FF00, mCheckedTextView.getCheckMarkTintList().getDefaultColor());
+        checkMark = mCheckedTextView.getCheckMarkDrawable();
+        TestUtils.assertAllPixelsOfColor("Expected 50% green", checkMark,
+                checkMark.getIntrinsicWidth(), checkMark.getIntrinsicHeight(), false,
+                0x8000FF00, 1, true);
+
+        // With SRC_OVER we're expecting the translucent tint color to be drawn on top
+        // of the original red checkmark, creating a composite color fill as the result.
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mCheckedTextView,
+                () -> mCheckedTextView.setCheckMarkTintMode(PorterDuff.Mode.SRC_OVER));
+
+        assertEquals(PorterDuff.Mode.SRC_OVER, mCheckedTextView.getCheckMarkTintMode());
+        assertEquals(0x8000FF00, mCheckedTextView.getCheckMarkTintList().getDefaultColor());
+        checkMark = mCheckedTextView.getCheckMarkDrawable();
+        TestUtils.assertAllPixelsOfColor("Expected 50% green over full red", checkMark,
+                checkMark.getIntrinsicWidth(), checkMark.getIntrinsicHeight(), false,
+                TestUtils.compositeColors(0x8000FF00, Color.RED), 1, true);
+
+        // Switch to a different color for the underlying checkmark and verify that the
+        // currently configured tinting (50% green overlay) is still respected
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mCheckedTextView,
+                () -> mCheckedTextView.setCheckMarkDrawable(R.drawable.icon_yellow));
+        assertEquals(PorterDuff.Mode.SRC_OVER, mCheckedTextView.getCheckMarkTintMode());
+        assertEquals(0x8000FF00, mCheckedTextView.getCheckMarkTintList().getDefaultColor());
+        checkMark = mCheckedTextView.getCheckMarkDrawable();
+        TestUtils.assertAllPixelsOfColor("Expected 50% green over full yellow", checkMark,
+                checkMark.getIntrinsicWidth(), checkMark.getIntrinsicHeight(), false,
+                TestUtils.compositeColors(0x8000FF00, Color.YELLOW), 1, true);
     }
 
     private static final class MockCheckedTextView extends CheckedTextView {
-        private boolean mHasRefreshDrawableState = false;
         private boolean mHasDrawableStateChanged = false;
 
         public MockCheckedTextView(Context context) {
@@ -320,10 +378,6 @@
             super(context, attrs, defStyle);
         }
 
-        public static int[] getSuperViewStateSet() {
-            return ENABLED_STATE_SET;
-        }
-
         @Override
         protected void drawableStateChanged() {
             super.drawableStateChanged();
@@ -340,24 +394,9 @@
             super.onDraw(canvas);
         }
 
-        @Override
-        public void refreshDrawableState() {
-            mHasRefreshDrawableState = true;
-            super.refreshDrawableState();
-        }
-
-        public boolean hasRefreshDrawableState() {
-            return mHasRefreshDrawableState;
-        }
-
         public boolean hasDrawableStateChanged() {
             return mHasDrawableStateChanged;
         }
-
-        public void reset() {
-            mHasRefreshDrawableState = false;
-            mHasDrawableStateChanged = false;
-        }
     }
 
     private class CheckedTextViewAdapter extends BaseAdapter {
diff --git a/tests/tests/widget/src/android/widget/cts/ChronometerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ChronometerCtsActivity.java
index 7925b49..affe740 100644
--- a/tests/tests/widget/src/android/widget/cts/ChronometerCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ChronometerCtsActivity.java
@@ -16,11 +16,11 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.ViewGroup;
 import android.widget.Chronometer;
+import android.widget.cts.R;
 
 public class ChronometerCtsActivity extends Activity {
 
diff --git a/tests/tests/widget/src/android/widget/cts/ChronometerTest.java b/tests/tests/widget/src/android/widget/cts/ChronometerTest.java
index ff1435f..1d5854a 100644
--- a/tests/tests/widget/src/android/widget/cts/ChronometerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ChronometerTest.java
@@ -16,28 +16,52 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
 
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.ContextThemeWrapper;
 import android.widget.Chronometer;
-import android.widget.Chronometer.OnChronometerTickListener;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link Chronometer}.
  */
-public class ChronometerTest extends ActivityInstrumentationTestCase2<ChronometerCtsActivity> {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ChronometerTest {
+    private Instrumentation mInstrumentation;
     private ChronometerCtsActivity mActivity;
-    public ChronometerTest() {
-        super("android.widget.cts", ChronometerCtsActivity.class);
+
+    @Rule
+    public ActivityTestRule<ChronometerCtsActivity> mActivityRule
+            = new ActivityTestRule<>(ChronometerCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    @UiThreadTest
+    @Test
     public void testConstructor() {
         new Chronometer(mActivity);
 
@@ -46,36 +70,48 @@
         new Chronometer(mActivity, null, 0);
     }
 
-    @UiThreadTest
+    @Test
+    public void testConstructorFromAttr() {
+        final Context context = new ContextThemeWrapper(mActivity, R.style.ChronometerAwareTheme);
+        final Chronometer chronometer = new Chronometer(context, null, R.attr.chronometerStyle);
+        assertTrue(chronometer.isCountDown());
+        assertEquals(mActivity.getString(R.string.chronometer_format), chronometer.getFormat());
+    }
+
+    @Test
+    public void testConstructorFromStyle() {
+        final Chronometer chronometer = new Chronometer(mActivity, null, 0,
+                R.style.ChronometerStyle);
+        assertTrue(chronometer.isCountDown());
+        assertEquals(mActivity.getString(R.string.chronometer_format), chronometer.getFormat());
+    }
+
+    @Test
     public void testAccessBase() {
         Chronometer chronometer = mActivity.getChronometer();
         CharSequence oldText = chronometer.getText();
 
-        int expected = 100000;
-        chronometer.setBase(expected);
-        assertEquals(expected, chronometer.getBase());
+        mInstrumentation.runOnMainSync(() -> chronometer.setBase(100000));
+        assertEquals(100000, chronometer.getBase());
         assertNotSame(oldText, chronometer.getText());
 
-        expected = 100;
         oldText = chronometer.getText();
-        chronometer.setBase(expected);
-        assertEquals(expected, chronometer.getBase());
+        mInstrumentation.runOnMainSync(() -> chronometer.setBase(100));
+        assertEquals(100, chronometer.getBase());
         assertNotSame(oldText, chronometer.getText());
 
-        expected = -1;
         oldText = chronometer.getText();
-        chronometer.setBase(expected);
-        assertEquals(expected, chronometer.getBase());
+        mInstrumentation.runOnMainSync(() -> chronometer.setBase(-1));
+        assertEquals(-1, chronometer.getBase());
         assertNotSame(oldText, chronometer.getText());
 
-        expected = Integer.MAX_VALUE;
         oldText = chronometer.getText();
-        chronometer.setBase(expected);
-        assertEquals(expected, chronometer.getBase());
+        mInstrumentation.runOnMainSync(() -> chronometer.setBase(Integer.MAX_VALUE));
+        assertEquals(Integer.MAX_VALUE, chronometer.getBase());
         assertNotSame(oldText, chronometer.getText());
     }
 
-    @UiThreadTest
+    @Test
     public void testAccessFormat() {
         Chronometer chronometer = mActivity.getChronometer();
         String expected = "header-%S-trail";
@@ -83,85 +119,106 @@
         chronometer.setFormat(expected);
         assertEquals(expected, chronometer.getFormat());
 
-        chronometer.start();
+        mInstrumentation.runOnMainSync(() -> chronometer.start());
         String text = chronometer.getText().toString();
         assertTrue(text.startsWith("header"));
         assertTrue(text.endsWith("trail"));
     }
 
-    public void testFoo() {
-        // Do not test these APIs. They are callbacks which:
-        // 1. The callback machanism has been tested in super class
-        // 2. The functionality is implmentation details, no need to test
-    }
-
-    public void testStartAndStop() throws Throwable {
+    @Test
+    @LargeTest
+    public void testStartAndStop() {
         final Chronometer chronometer = mActivity.getChronometer();
 
         // we will check the text is really updated every 1000ms after start,
         // so we need sleep a moment to wait wait this time. The sleep code shouldn't
         // in the same thread with UI, that's why we use runOnMainSync here.
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                // the text will update immediately when call start.
-                CharSequence expected = chronometer.getText();
-                chronometer.start();
-                assertNotSame(expected, chronometer.getText());
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            // the text will update immediately when call start.
+            final CharSequence valueBeforeStart = chronometer.getText();
+            chronometer.start();
+            assertNotSame(valueBeforeStart, chronometer.getText());
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
+
         CharSequence expected = chronometer.getText();
-        Thread.sleep(1500);
+        SystemClock.sleep(1500);
         assertFalse(expected.equals(chronometer.getText()));
 
         // we will check the text is really NOT updated anymore every 1000ms after stop,
         // so we need sleep a moment to wait wait this time. The sleep code shouldn't
         // in the same thread with UI, that's why we use runOnMainSync here.
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                // the text will never be updated when call stop.
-                CharSequence expected = chronometer.getText();
-                chronometer.stop();
-                assertSame(expected, chronometer.getText());
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            // the text will never be updated when call stop.
+            final CharSequence valueBeforeStop = chronometer.getText();
+            chronometer.stop();
+            assertSame(valueBeforeStop, chronometer.getText());
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
+
         expected = chronometer.getText();
-        Thread.sleep(1500);
+        SystemClock.sleep(1500);
         assertTrue(expected.equals(chronometer.getText()));
     }
 
-    public void testAccessOnChronometerTickListener() throws Throwable {
+    @Test
+    @LargeTest
+    public void testAccessOnChronometerTickListener() {
         final Chronometer chronometer = mActivity.getChronometer();
-        final MockOnChronometerTickListener listener = new MockOnChronometerTickListener();
+        final Chronometer.OnChronometerTickListener mockTickListener =
+                mock(Chronometer.OnChronometerTickListener.class);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                chronometer.setOnChronometerTickListener(listener);
-                chronometer.start();
-            }
+        mInstrumentation.runOnMainSync(() -> {
+            chronometer.setOnChronometerTickListener(mockTickListener);
+            chronometer.start();
         });
-        getInstrumentation().waitForIdleSync();
-        assertEquals(listener, chronometer.getOnChronometerTickListener());
-        assertTrue(listener.hasCalledOnChronometerTick());
-        listener.reset();
-        Thread.sleep(1500);
-        assertTrue(listener.hasCalledOnChronometerTick());
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(mockTickListener, chronometer.getOnChronometerTickListener());
+        verify(mockTickListener, atLeastOnce()).onChronometerTick(chronometer);
+
+        reset(mockTickListener);
+        SystemClock.sleep(1500);
+        verify(mockTickListener, atLeastOnce()).onChronometerTick(chronometer);
     }
 
-    private static class MockOnChronometerTickListener implements OnChronometerTickListener {
-        private boolean mCalledOnChronometerTick = false;
+    @Test
+    @LargeTest
+    public void testCountDown() {
+        final Chronometer chronometer = mActivity.getChronometer();
+        final Chronometer.OnChronometerTickListener mockTickListener =
+                mock(Chronometer.OnChronometerTickListener.class);
 
-        public void onChronometerTick(Chronometer chronometer) {
-            mCalledOnChronometerTick = true;
-        }
+        mInstrumentation.runOnMainSync(() -> {
+            chronometer.setCountDown(true);
+            chronometer.setOnChronometerTickListener(mockTickListener);
+            chronometer.start();
+        });
+        mInstrumentation.waitForIdleSync();
 
-        public boolean hasCalledOnChronometerTick() {
-            return mCalledOnChronometerTick;
-        }
+        assertTrue(chronometer.isCountDown());
 
-        public void reset() {
-            mCalledOnChronometerTick = false;
-        }
+        SystemClock.sleep(5000);
+        verify(mockTickListener, atLeastOnce()).onChronometerTick(chronometer);
+    }
+
+    @Test
+    @LargeTest
+    public void testCountUp() {
+        final Chronometer chronometer = mActivity.getChronometer();
+        final Chronometer.OnChronometerTickListener mockTickListener =
+                mock(Chronometer.OnChronometerTickListener.class);
+
+        mInstrumentation.runOnMainSync(() -> {
+            chronometer.setCountDown(false);
+            chronometer.setOnChronometerTickListener(mockTickListener);
+            chronometer.start();
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(chronometer.isCountDown());
+
+        SystemClock.sleep(5000);
+        verify(mockTickListener, atLeastOnce()).onChronometerTick(chronometer);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java b/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
index 34d94a5..505a9b0 100644
--- a/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
@@ -16,45 +16,65 @@
 
 package android.widget.cts;
 
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.PorterDuff;
-import android.view.LayoutInflater;
-import android.widget.ToggleButton;
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.StateSet;
 import android.util.Xml;
 import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ToggleButton;
+import android.widget.cts.util.TestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
 /**
  * Test {@link CompoundButton}.
  */
-public class CompoundButtonTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CompoundButtonTest  {
+    private Context mContext;
     private Resources mResources;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         mResources = mContext.getResources();
     }
 
+    @Test
     public void testConstructor() {
         XmlPullParser parser = mContext.getResources().getXml(R.layout.togglebutton_layout);
         AttributeSet mAttrSet = Xml.asAttributeSet(parser);
@@ -62,71 +82,66 @@
         new MockCompoundButton(mContext, mAttrSet, 0);
         new MockCompoundButton(mContext, mAttrSet);
         new MockCompoundButton(mContext);
-
-        try {
-            new MockCompoundButton(null, null, -1);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new MockCompoundButton(null, null);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new MockCompoundButton(null);
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new MockCompoundButton(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new MockCompoundButton(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new MockCompoundButton(null, null, -1);
+    }
+
+    @Test
     public void testAccessChecked() {
         CompoundButton compoundButton = new MockCompoundButton(mContext);
-        MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
-        compoundButton.setOnCheckedChangeListener(listener);
+        CompoundButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CompoundButton.OnCheckedChangeListener.class);
+        compoundButton.setOnCheckedChangeListener(mockCheckedChangeListener);
         assertFalse(compoundButton.isChecked());
-        assertFalse(listener.hasCalledCheckedChange());
+        verifyZeroInteractions(mockCheckedChangeListener);
 
         compoundButton.setChecked(true);
         assertTrue(compoundButton.isChecked());
-        assertTrue(listener.hasCalledCheckedChange());
-        assertSame(compoundButton, listener.getInputCompoundButton());
-        assertTrue(listener.getInputChecked());
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(compoundButton, true);
 
-        listener.reset();
+        reset(mockCheckedChangeListener);
         compoundButton.setChecked(true);
         assertTrue(compoundButton.isChecked());
-        assertFalse(listener.hasCalledCheckedChange());
+        verifyZeroInteractions(mockCheckedChangeListener);
 
         compoundButton.setChecked(false);
         assertFalse(compoundButton.isChecked());
-        assertTrue(listener.hasCalledCheckedChange());
-        assertSame(compoundButton, listener.getInputCompoundButton());
-        assertFalse(listener.getInputChecked());
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(compoundButton, false);
     }
 
+    @Test
     public void testSetOnCheckedChangeListener() {
         CompoundButton compoundButton = new MockCompoundButton(mContext);
-        MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
-        compoundButton.setOnCheckedChangeListener(listener);
+        CompoundButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CompoundButton.OnCheckedChangeListener.class);
+        compoundButton.setOnCheckedChangeListener(mockCheckedChangeListener);
         assertFalse(compoundButton.isChecked());
-        assertFalse(listener.hasCalledCheckedChange());
+        verifyZeroInteractions(mockCheckedChangeListener);
 
         compoundButton.setChecked(true);
-        assertTrue(listener.hasCalledCheckedChange());
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(compoundButton, true);
 
         // set null
         compoundButton.setOnCheckedChangeListener(null);
-        listener.reset();
+        reset(mockCheckedChangeListener);
         compoundButton.setChecked(false);
-        assertFalse(listener.hasCalledCheckedChange());
+        verifyZeroInteractions(mockCheckedChangeListener);
     }
 
+    @Test
     public void testToggle() {
         CompoundButton compoundButton = new MockCompoundButton(mContext);
         assertFalse(compoundButton.isChecked());
@@ -142,6 +157,7 @@
         assertFalse(compoundButton.isChecked());
     }
 
+    @Test
     public void testPerformClick() {
         CompoundButton compoundButton = new MockCompoundButton(mContext);
         assertFalse(compoundButton.isChecked());
@@ -154,10 +170,7 @@
         assertFalse(compoundButton.isChecked());
 
         // performClick with OnClickListener will return true.
-        compoundButton.setOnClickListener(new OnClickListener() {
-            public void onClick(View v) {
-            }
-        });
+        compoundButton.setOnClickListener((view) -> {});
         assertTrue(compoundButton.performClick());
         assertTrue(compoundButton.isChecked());
 
@@ -165,6 +178,7 @@
         assertFalse(compoundButton.isChecked());
     }
 
+    @Test
     public void testDrawableStateChanged() {
         MockCompoundButton compoundButton = new MockCompoundButton(mContext);
         assertFalse(compoundButton.isChecked());
@@ -182,6 +196,7 @@
         assertSame(compoundButton.getDrawableState(), drawable.getState());
     }
 
+    @Test
     public void testSetButtonDrawableByDrawable() {
         CompoundButton compoundButton;
 
@@ -214,6 +229,7 @@
         assertFalse(firstDrawable.isVisible());
     }
 
+    @Test
     public void testSetButtonDrawableById() {
         CompoundButton compoundButton;
         // resId is 0
@@ -231,6 +247,7 @@
         compoundButton.setButtonDrawable(R.drawable.pass);
     }
 
+    @Test
     public void testOnCreateDrawableState() {
         MockCompoundButton compoundButton;
 
@@ -252,6 +269,7 @@
         assertEquals(0, state[state.length - 1]);
     }
 
+    @Test
     public void testOnDraw() {
         int viewHeight;
         int drawableWidth;
@@ -300,6 +318,7 @@
         assertEquals( (viewHeight - drawableHeight) / 2 + drawableHeight, bounds.bottom);
     }
 
+    @Test
     public void testAccessInstanceState() {
         CompoundButton compoundButton = new MockCompoundButton(mContext);
         Parcelable state;
@@ -318,6 +337,7 @@
         assertTrue(compoundButton.isLayoutRequested());
     }
 
+    @Test
     public void testVerifyDrawable() {
         MockCompoundButton compoundButton = new MockCompoundButton(mContext);
         Drawable drawable = mContext.getResources().getDrawable(R.drawable.scenery);
@@ -330,6 +350,7 @@
         assertTrue(compoundButton.verifyDrawable(drawable));
     }
 
+    @Test
     public void testButtonTint() {
         LayoutInflater inflater = LayoutInflater.from(mContext);
         View layout = inflater.inflate(R.layout.togglebutton_layout, null);
@@ -340,53 +361,22 @@
         assertEquals("Button tint mode inflated correctly",
                 PorterDuff.Mode.SRC_OVER, inflatedView.getButtonTintMode());
 
-        MockDrawable button = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.GREEN));
         CompoundButton view = new ToggleButton(mContext);
 
-        view.setButtonDrawable(button);
-        assertFalse("No button tint applied by default", button.hasCalledSetTint());
+        view.setButtonDrawable(mockDrawable);
+        // No button tint applied by default
+        verify(mockDrawable, never()).setTintList(any(ColorStateList.class));
 
         view.setButtonTintList(ColorStateList.valueOf(Color.WHITE));
-        assertTrue("Button tint applied when setButtonTintList() called after setButton()",
-                button.hasCalledSetTint());
+        // Button tint applied when setButtonTintList() called after setButton()
+        verify(mockDrawable, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
 
-        button.reset();
+        reset(mockDrawable);
         view.setButtonDrawable(null);
-        view.setButtonDrawable(button);
-        assertTrue("Button tint applied when setButtonTintList() called before setButton()",
-                button.hasCalledSetTint());
-    }
-
-    private static class MockDrawable extends Drawable {
-        private boolean mCalledSetTint = false;
-
-        @Override
-        public void draw(Canvas canvas) {}
-
-        @Override
-        public void setAlpha(int alpha) {}
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {}
-
-        @Override
-        public void setTintList(ColorStateList tint) {
-            super.setTintList(tint);
-            mCalledSetTint = true;
-        }
-
-        @Override
-        public int getOpacity() {
-            return 0;
-        }
-
-        public boolean hasCalledSetTint() {
-            return mCalledSetTint;
-        }
-
-        public void reset() {
-            mCalledSetTint = false;
-        }
+        view.setButtonDrawable(mockDrawable);
+        // Button tint applied when setButtonTintList() called before setButton()
+        verify(mockDrawable, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
     }
 
     private final class MockCompoundButton extends CompoundButton {
@@ -422,34 +412,4 @@
             return super.verifyDrawable(who);
         }
     }
-
-    private final class MockOnCheckedChangeListener implements OnCheckedChangeListener {
-        private boolean mHasCalledChecked;
-        private CompoundButton mCompoundButton;
-        private boolean mIsChecked;
-
-        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-            mHasCalledChecked = true;
-            mCompoundButton = buttonView;
-            mIsChecked = isChecked;
-        }
-
-        public boolean getInputChecked() {
-            return mIsChecked;
-        }
-
-        public CompoundButton getInputCompoundButton() {
-            return mCompoundButton;
-        }
-
-        public boolean hasCalledCheckedChange() {
-            return mHasCalledChecked;
-        }
-
-        public void reset() {
-            mHasCalledChecked = false;
-            mCompoundButton = null;
-            mIsChecked = false;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
index 8ef414d..2cab66c 100644
--- a/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import java.io.File;
+import static org.mockito.Mockito.*;
 
 import android.content.Context;
 import android.database.Cursor;
@@ -31,9 +31,10 @@
 import android.widget.Filter;
 import android.widget.FilterQueryProvider;
 import android.widget.TextView;
-
 import android.widget.cts.R;
 
+import java.io.File;
+
 
 /**
  * Test {@link CursorTreeAdapter}.
@@ -199,23 +200,23 @@
     @UiThreadTest
     public void testNotifyDataSetChangedBoolean() {
         MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
-        MockDataSetObserver observer = new MockDataSetObserver();
-        adapter.registerDataSetObserver(observer);
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        adapter.registerDataSetObserver(mockDataSetObserver);
 
         // mChildrenCursorHelpers is empty
-        assertFalse(observer.hasCalledOnChanged());
+        verifyZeroInteractions(mockDataSetObserver);
         adapter.notifyDataSetChanged(false);
-        assertTrue(observer.hasCalledOnChanged());
+        verify(mockDataSetObserver, times(1)).onChanged();
 
         // add group 0 into mChildrenCursorHelpers
         adapter.getChild(0, 0);
         // add group 1 into mChildrenCursorHelpers
         adapter.getChild(1, 0);
-        observer.reset();
-        assertFalse(observer.hasCalledOnChanged());
+        reset(mockDataSetObserver);
+        verifyZeroInteractions(mockDataSetObserver);
 
         adapter.notifyDataSetChanged(true);
-        assertTrue(observer.hasCalledOnChanged());
+        verify(mockDataSetObserver, times(1)).onChanged();
         adapter.reset();
         adapter.getChild(0, 0);
         assertTrue(adapter.hasAddedChild1IntoCache());
@@ -223,11 +224,11 @@
         assertTrue(adapter.hasAddedChild2IntoCache());
 
         // both group 0 and group 1 are in mChildrenCursorHelpers
-        observer.reset();
-        assertFalse(observer.hasCalledOnChanged());
+        reset(mockDataSetObserver);
+        verifyZeroInteractions(mockDataSetObserver);
         // does not release cursors
         adapter.notifyDataSetChanged(false);
-        assertTrue(observer.hasCalledOnChanged());
+        verify(mockDataSetObserver, times(1)).onChanged();
         adapter.reset();
         adapter.getChild(0, 0);
         assertFalse(adapter.hasAddedChild1IntoCache());
@@ -238,22 +239,22 @@
     @UiThreadTest
     public void testNotifyDataSetChanged() {
         MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
-        MockDataSetObserver observer = new MockDataSetObserver();
-        adapter.registerDataSetObserver(observer);
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        adapter.registerDataSetObserver(mockDataSetObserver);
 
         // mChildrenCursorHelpers is empty
-        assertFalse(observer.hasCalledOnChanged());
+        verifyZeroInteractions(mockDataSetObserver);
         adapter.notifyDataSetChanged();
-        assertTrue(observer.hasCalledOnChanged());
+        verify(mockDataSetObserver, times(1)).onChanged();
 
         // add group 0 into mChildrenCursorHelpers
         adapter.getChild(0, 0);
         // add group 1 into mChildrenCursorHelpers
         adapter.getChild(1, 0);
-        observer.reset();
-        assertFalse(observer.hasCalledOnChanged());
+        reset(mockDataSetObserver);
+        verifyZeroInteractions(mockDataSetObserver);
         adapter.notifyDataSetChanged();
-        assertTrue(observer.hasCalledOnChanged());
+        verify(mockDataSetObserver, times(1)).onChanged();
         adapter.reset();
         adapter.getChild(0, 0);
         assertTrue(adapter.hasAddedChild1IntoCache());
@@ -264,22 +265,22 @@
     @UiThreadTest
     public void testNotifyDataSetInvalidated() {
         MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
-        MockDataSetObserver observer = new MockDataSetObserver();
-        adapter.registerDataSetObserver(observer);
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        adapter.registerDataSetObserver(mockDataSetObserver);
 
-        assertFalse(observer.hasCalledOnInvalidated());
+        verifyZeroInteractions(mockDataSetObserver);
         // mChildrenCursorHelpers is empty
         adapter.notifyDataSetInvalidated();
-        assertTrue(observer.hasCalledOnInvalidated());
+        verify(mockDataSetObserver, times(1)).onInvalidated();
 
         // add group 0 into mChildrenCursorHelpers
         adapter.getChild(0, 0);
         // add group 1 into mChildrenCursorHelpers
         adapter.getChild(1, 0);
-        observer.reset();
-        assertFalse(observer.hasCalledOnInvalidated());
+        reset(mockDataSetObserver);
+        verifyZeroInteractions(mockDataSetObserver);
         adapter.notifyDataSetInvalidated();
-        assertTrue(observer.hasCalledOnInvalidated());
+        verify(mockDataSetObserver, times(1)).onInvalidated();
         adapter.reset();
         adapter.getChild(0, 0);
         assertTrue(adapter.hasAddedChild1IntoCache());
@@ -707,34 +708,4 @@
             return null;
         }
     }
-
-    private final class MockDataSetObserver extends DataSetObserver {
-        private boolean mHasCalledOnChanged = false;
-        private boolean mHasCalledOnInvalidated = false;
-
-        @Override
-        public void onChanged() {
-            super.onChanged();
-            mHasCalledOnChanged = true;
-        }
-
-        @Override
-        public void onInvalidated() {
-            super.onInvalidated();
-            mHasCalledOnInvalidated = true;
-        }
-
-        public boolean hasCalledOnChanged() {
-            return mHasCalledOnChanged;
-        }
-
-        public boolean hasCalledOnInvalidated() {
-            return mHasCalledOnInvalidated;
-        }
-
-        public void reset() {
-            mHasCalledOnChanged = false;
-            mHasCalledOnInvalidated = false;
-        }
-    }
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/DatePickerCtsActivity.java
similarity index 67%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/DatePickerCtsActivity.java
index 481f5be..81e6e69 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.DatePicker;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link DatePicker} test.
+ */
+public class DatePickerCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.datepicker_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/DatePickerDialogTest.java b/tests/tests/widget/src/android/widget/cts/DatePickerDialogTest.java
index 1477f73..177a9f8 100644
--- a/tests/tests/widget/src/android/widget/cts/DatePickerDialogTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerDialogTest.java
@@ -16,75 +16,77 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.DatePickerDialog;
-import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link DatePickerDialog}.
  */
-public class DatePickerDialogTest extends
-        ActivityInstrumentationTestCase2<DatePickerDialogCtsActivity> {
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class DatePickerDialogTest {
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
+    private DatePickerDialog mDatePickerDialog;
 
-    public DatePickerDialogTest() {
-        super(DatePickerDialogCtsActivity.class);
+    @Rule
+    public ActivityTestRule<DatePickerDialogCtsActivity> mActivityRule
+            = new ActivityTestRule<>(DatePickerDialogCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    @UiThreadTest
-    @SuppressWarnings("deprecation")
+    @Test
     public void testConstructor() {
-        new DatePickerDialog(mActivity, null, 1970, 1, 1);
+        mInstrumentation.runOnMainSync(() -> {
+                new DatePickerDialog(mActivity, null, 1970, 1, 1);
 
-        new DatePickerDialog(mActivity, AlertDialog.THEME_TRADITIONAL, null, 1970, 1, 1);
+                new DatePickerDialog(mActivity, AlertDialog.THEME_TRADITIONAL, null, 1970, 1, 1);
 
-        new DatePickerDialog(mActivity, AlertDialog.THEME_HOLO_DARK, null, 1970, 1, 1);
+                new DatePickerDialog(mActivity, AlertDialog.THEME_HOLO_DARK, null, 1970, 1, 1);
 
-        new DatePickerDialog(mActivity,
-                android.R.style.Theme_Material_Dialog_Alert, null, 1970, 1, 1);
-
-        try {
-            new DatePickerDialog(null, null, 1970, 1, 1);
-            fail("should throw NullPointerException");
-        } catch (Exception e) {
-        }
+                new DatePickerDialog(mActivity,
+                        android.R.style.Theme_Material_Dialog_Alert, null, 1970, 1, 1);
+        });
     }
 
-    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext() {
+        new DatePickerDialog(null, null, 1970, 1, 1);
+    }
+
+    @Test
     public void testShowDismiss() {
-        DatePickerDialog d = createDatePickerDialog();
+        mInstrumentation.runOnMainSync(
+                () -> mDatePickerDialog = new DatePickerDialog(mActivity, null, 1970, 1, 1));
 
-        d.show();
-        assertTrue("Showing date picker", d.isShowing());
+        mInstrumentation.runOnMainSync(mDatePickerDialog::show);
+        assertTrue("Showing date picker", mDatePickerDialog.isShowing());
 
-        d.show();
-        assertTrue("Date picker still showing", d.isShowing());
+        mInstrumentation.runOnMainSync(mDatePickerDialog::show);
+        assertTrue("Date picker still showing", mDatePickerDialog.isShowing());
 
-        d.dismiss();
-        assertFalse("Dismissed date picker", d.isShowing());
+        mInstrumentation.runOnMainSync(mDatePickerDialog::dismiss);
+        assertFalse("Dismissed date picker", mDatePickerDialog.isShowing());
 
-        d.dismiss();
-        assertFalse("Date picker still dismissed", d.isShowing());
-    }
-
-    private MockDatePickerDialog createDatePickerDialog() {
-        return new MockDatePickerDialog(mActivity, null, 1970, 1, 1);
-    }
-
-    private class MockDatePickerDialog extends DatePickerDialog {
-        public MockDatePickerDialog(Context context, OnDateSetListener callBack,
-                int year, int monthOfYear, int dayOfMonth) {
-            super(context, callBack, year, monthOfYear, dayOfMonth);
-        }
+        mInstrumentation.runOnMainSync(mDatePickerDialog::dismiss);
+        assertFalse("Date picker still dismissed", mDatePickerDialog.isShowing());
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/DatePickerTest.java b/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
index c48f684..45a3aac 100644
--- a/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
@@ -16,120 +16,258 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.mockito.Mockito.*;
 
+import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
-import android.content.res.XmlResourceParser;
 import android.os.Parcelable;
-import android.test.InstrumentationTestCase;
+import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
-import android.util.AttributeSet;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.util.SparseArray;
-import android.util.Xml;
 import android.view.View;
 import android.widget.DatePicker;
-import android.widget.cts.util.XmlUtils;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
 
 /**
  * Test {@link DatePicker}.
  */
-public class DatePickerTest extends InstrumentationTestCase {
+@MediumTest
+public class DatePickerTest extends ActivityInstrumentationTestCase2<DatePickerCtsActivity> {
+    private Activity mActivity;
+    private DatePicker mDatePickerSpinnerMode;
+    private DatePicker mDatePickerCalendarMode;
 
-    private Context mContext;
+    public DatePickerTest() {
+        super("android.widget.cts", DatePickerCtsActivity.class);
+    }
 
     @Override
-    public void setUp() {
-        mContext = getInstrumentation().getTargetContext();
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mDatePickerSpinnerMode = (DatePicker) mActivity.findViewById(R.id.date_picker_spinner_mode);
+        mDatePickerCalendarMode =
+                (DatePicker) mActivity.findViewById(R.id.date_picker_calendar_mode);
     }
 
-    @UiThreadTest
     public void testConstructor() {
-        new DatePicker(mContext);
+        new DatePicker(mActivity);
 
-        new DatePicker(mContext, null);
+        new DatePicker(mActivity, null);
 
-        new DatePicker(mContext, getAttributeSet(R.layout.datepicker_layout));
+        new DatePicker(mActivity, null, android.R.attr.datePickerStyle);
 
-        new DatePicker(mContext, getAttributeSet(R.layout.datepicker_layout), 0);
+        new DatePicker(mActivity, null, 0, android.R.style.Widget_DeviceDefault_DatePicker);
 
-        // Test constructor with null Context, in fact, previous two functions will finally invoke
-        // this version.
-        try {
-            // Test with null Context
-            new DatePicker(null, getAttributeSet(R.layout.datepicker_layout), 0);
-            fail("should throw NullPointerException");
-        } catch (Exception e) {
-        }
+        new DatePicker(mActivity, null, 0, android.R.style.Widget_Material_DatePicker);
+
+        new DatePicker(mActivity, null, 0, android.R.style.Widget_Material_Light_DatePicker);
     }
 
-    @UiThreadTest
     public void testSetEnabled() {
-        MockDatePicker datePicker = createDatePicker();
+        final Instrumentation instrumentation = getInstrumentation();
 
-        assertTrue(datePicker.isEnabled());
+        assertTrue(mDatePickerCalendarMode.isEnabled());
 
-        datePicker.setEnabled(false);
-        assertFalse(datePicker.isEnabled());
+        instrumentation.runOnMainSync(() -> mDatePickerCalendarMode.setEnabled(false));
+        assertFalse(mDatePickerCalendarMode.isEnabled());
 
-        datePicker.setEnabled(true);
-        assertTrue(datePicker.isEnabled());
+        instrumentation.runOnMainSync(() -> mDatePickerCalendarMode.setEnabled(true));
+        assertTrue(mDatePickerCalendarMode.isEnabled());
     }
 
-    @UiThreadTest
+    private void verifyInit(DatePicker datePicker) {
+        final Instrumentation instrumentation = getInstrumentation();
+        final DatePicker.OnDateChangedListener mockDateChangeListener =
+                mock(DatePicker.OnDateChangedListener.class);
+
+        instrumentation.runOnMainSync(
+                () -> datePicker.init(2000, 10, 15, mockDateChangeListener));
+        assertEquals(2000, datePicker.getYear());
+        assertEquals(10, datePicker.getMonth());
+        assertEquals(15, datePicker.getDayOfMonth());
+
+        verifyZeroInteractions(mockDateChangeListener);
+    }
+
     public void testInit() {
-        MockOnDateChangedListener onDateChangedListener = new MockOnDateChangedListener();
-        DatePicker datePicker = createDatePicker();
+        verifyInit(mDatePickerSpinnerMode);
+        verifyInit(mDatePickerCalendarMode);
+    }
 
-        /* The month display uses 1-12 but our internal state stores it
-         * 0-11 so add one when setting the display.
-         */
-        datePicker.init(2000, 10, 15, onDateChangedListener);
+    private void verifyAccessDate(DatePicker datePicker) {
+        final Instrumentation instrumentation = getInstrumentation();
+        final DatePicker.OnDateChangedListener mockDateChangeListener =
+                mock(DatePicker.OnDateChangedListener.class);
+
+        instrumentation.runOnMainSync(() -> datePicker.init(2000, 10, 15, mockDateChangeListener));
         assertEquals(2000, datePicker.getYear());
         assertEquals(10, datePicker.getMonth());
         assertEquals(15, datePicker.getDayOfMonth());
+        verify(mockDateChangeListener, never()).onDateChanged(any(DatePicker.class), anyInt(),
+                anyInt(), anyInt());
+
+        instrumentation.runOnMainSync(() -> datePicker.updateDate(1989, 9, 19));
+        assertEquals(1989, datePicker.getYear());
+        assertEquals(9, datePicker.getMonth());
+        assertEquals(19, datePicker.getDayOfMonth());
+        verify(mockDateChangeListener, times(1)).onDateChanged(datePicker, 1989, 9, 19);
+
+        verifyNoMoreInteractions(mockDateChangeListener);
     }
 
-    @UiThreadTest
     public void testAccessDate() {
-        DatePicker datePicker = createDatePicker();
+        verifyAccessDate(mDatePickerSpinnerMode);
+        verifyAccessDate(mDatePickerCalendarMode);
+    }
 
-        /* The month display uses 1-12 but our internal state stores it
-         * 0-11 so add one when setting the display.
-         */
-        MockOnDateChangedListener onDateChangedListener = new MockOnDateChangedListener();
-        datePicker.init(2000, 10, 15, onDateChangedListener);
+    private void verifySetOnDateChangedListener(DatePicker datePicker) {
+        final Instrumentation instrumentation = getInstrumentation();
+        final DatePicker.OnDateChangedListener mockDateChangeListener1 =
+                mock(DatePicker.OnDateChangedListener.class);
+        final DatePicker.OnDateChangedListener mockDateChangeListener2 =
+                mock(DatePicker.OnDateChangedListener.class);
+
+        instrumentation.runOnMainSync(() -> datePicker.init(2000, 10, 15, mockDateChangeListener1));
+        instrumentation.runOnMainSync(() -> datePicker.updateDate(1989, 9, 19));
+        assertEquals(1989, datePicker.getYear());
+        assertEquals(9, datePicker.getMonth());
+        assertEquals(19, datePicker.getDayOfMonth());
+        verify(mockDateChangeListener1, times(1)).onDateChanged(datePicker, 1989, 9, 19);
+        verify(mockDateChangeListener2, times(0)).onDateChanged(datePicker, 1989, 9, 19);
+
+        instrumentation.runOnMainSync(() -> datePicker.setOnDateChangedListener(
+                mockDateChangeListener2));
+        instrumentation.runOnMainSync(() -> datePicker.updateDate(2000, 10, 15));
         assertEquals(2000, datePicker.getYear());
         assertEquals(10, datePicker.getMonth());
         assertEquals(15, datePicker.getDayOfMonth());
+        verify(mockDateChangeListener1, times(0)).onDateChanged(datePicker, 2000, 10, 15);
+        verify(mockDateChangeListener2, times(1)).onDateChanged(datePicker, 2000, 10, 15);
 
-        datePicker.updateDate(1989, 9, 19);
+    }
+
+    public void testSetOnDateChangedListener() {
+        verifySetOnDateChangedListener(mDatePickerSpinnerMode);
+        verifySetOnDateChangedListener(mDatePickerCalendarMode);
+    }
+
+    private void verifyUpdateDate(DatePicker datePicker) {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        instrumentation.runOnMainSync(() -> datePicker.updateDate(1989, 9, 19));
         assertEquals(1989, datePicker.getYear());
         assertEquals(9, datePicker.getMonth());
         assertEquals(19, datePicker.getDayOfMonth());
     }
 
-    @UiThreadTest
     public void testUpdateDate() {
-        DatePicker datePicker = createDatePicker();
+        verifyUpdateDate(mDatePickerSpinnerMode);
+        verifyUpdateDate(mDatePickerCalendarMode);
+    }
 
-        // Test normal input values
-        /* The month display uses 1-12 but our internal state stores it
-         * 0-11 so add one when setting the display.
-         */
-        datePicker.updateDate(1989, 9, 19);
-        assertEquals(1989, datePicker.getYear());
-        assertEquals(9, datePicker.getMonth());
-        assertEquals(19, datePicker.getDayOfMonth());
+    private void verifyMinMaxDate(DatePicker datePicker) {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // Use a range of minus/plus one year as min/max dates
+        final Calendar minCalendar = new GregorianCalendar();
+        minCalendar.set(Calendar.YEAR, minCalendar.get(Calendar.YEAR) - 1);
+        final Calendar maxCalendar = new GregorianCalendar();
+        maxCalendar.set(Calendar.YEAR, maxCalendar.get(Calendar.YEAR) + 1);
+
+        final long minDate = minCalendar.getTime().getTime();
+        final long maxDate = maxCalendar.getTime().getTime();
+
+        instrumentation.runOnMainSync(() -> {
+            datePicker.setMinDate(minDate);
+            datePicker.setMaxDate(maxDate);
+        });
+
+        assertEquals(datePicker.getMinDate(), minDate);
+        assertEquals(datePicker.getMaxDate(), maxDate);
+    }
+
+    public void testMinMaxDate() {
+        verifyMinMaxDate(mDatePickerSpinnerMode);
+        verifyMinMaxDate(mDatePickerCalendarMode);
+    }
+
+    private void verifyFirstDayOfWeek(DatePicker datePicker) {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        instrumentation.runOnMainSync(() -> datePicker.setFirstDayOfWeek(Calendar.TUESDAY));
+        assertEquals(Calendar.TUESDAY, datePicker.getFirstDayOfWeek());
+
+        instrumentation.runOnMainSync(() -> datePicker.setFirstDayOfWeek(Calendar.SUNDAY));
+        assertEquals(Calendar.SUNDAY, datePicker.getFirstDayOfWeek());
+    }
+
+    public void testFirstDayOfWeek() {
+        verifyFirstDayOfWeek(mDatePickerSpinnerMode);
+        verifyFirstDayOfWeek(mDatePickerCalendarMode);
+    }
+
+    public void testCalendarViewInSpinnerMode() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        assertNotNull(mDatePickerSpinnerMode.getCalendarView());
+
+        // Update the DatePicker and test that its CalendarView is synced to the same date
+        final Calendar calendar = new GregorianCalendar();
+        calendar.set(Calendar.YEAR, 2008);
+        calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);
+        calendar.set(Calendar.DAY_OF_MONTH, 23);
+        instrumentation.runOnMainSync(
+                () -> mDatePickerSpinnerMode.updateDate(
+                        calendar.get(Calendar.YEAR),
+                        calendar.get(Calendar.MONTH),
+                        calendar.get(Calendar.DAY_OF_MONTH)));
+
+        final Calendar calendarFromSpinner = new GregorianCalendar();
+        final long timeFromSpinnerCalendar = mDatePickerSpinnerMode.getCalendarView().getDate();
+        calendarFromSpinner.setTimeInMillis(timeFromSpinnerCalendar);
+
+        assertEquals(calendar.get(Calendar.YEAR), calendarFromSpinner.get(Calendar.YEAR));
+        assertEquals(calendar.get(Calendar.MONTH), calendarFromSpinner.get(Calendar.MONTH));
+        assertEquals(calendar.get(Calendar.DAY_OF_MONTH),
+                calendarFromSpinner.get(Calendar.DAY_OF_MONTH));
+    }
+
+    public void testPartsVisibilityInSpinnerMode() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        assertTrue(mDatePickerSpinnerMode.getSpinnersShown());
+        assertTrue(mDatePickerSpinnerMode.getCalendarViewShown());
+
+        instrumentation.runOnMainSync(() -> mDatePickerSpinnerMode.setSpinnersShown(false));
+        assertFalse(mDatePickerSpinnerMode.getSpinnersShown());
+        assertTrue(mDatePickerSpinnerMode.getCalendarViewShown());
+
+        instrumentation.runOnMainSync(() -> mDatePickerSpinnerMode.setCalendarViewShown(false));
+        assertFalse(mDatePickerSpinnerMode.getSpinnersShown());
+        assertFalse(mDatePickerSpinnerMode.getCalendarViewShown());
+
+        instrumentation.runOnMainSync(() -> mDatePickerSpinnerMode.setSpinnersShown(true));
+        assertTrue(mDatePickerSpinnerMode.getSpinnersShown());
+        assertFalse(mDatePickerSpinnerMode.getCalendarViewShown());
+
+        instrumentation.runOnMainSync(() -> mDatePickerSpinnerMode.setCalendarViewShown(true));
+        assertTrue(mDatePickerSpinnerMode.getSpinnersShown());
+        assertTrue(mDatePickerSpinnerMode.getCalendarViewShown());
     }
 
     @UiThreadTest
-    public void testOnSaveInstanceState() {
-        MockDatePicker datePicker = createDatePicker();
+    public void testAccessInstanceState() {
+        MockDatePicker datePicker = new MockDatePicker(mActivity);
 
         datePicker.updateDate(2008, 9, 10);
         SparseArray<Parcelable> container = new SparseArray<Parcelable>();
 
-        // Test onSaveHierarchyState
+        // Test saveHierarchyState -> onSaveInstanceState path
         assertEquals(View.NO_ID, datePicker.getId());
         datePicker.setId(99);
         assertFalse(datePicker.hasCalledOnSaveInstanceState());
@@ -137,43 +275,23 @@
         assertEquals(1, datePicker.getChildCount());
         assertTrue(datePicker.hasCalledOnSaveInstanceState());
 
-        // Test dispatchRestoreInstanceState
-        datePicker = createDatePicker();
+        // Test dispatchRestoreInstanceState -> onRestoreInstanceState path
+        datePicker = new MockDatePicker(mActivity);
         datePicker.setId(99);
         assertFalse(datePicker.hasCalledOnRestoreInstanceState());
         datePicker.dispatchRestoreInstanceState(container);
         assertEquals(2008, datePicker.getYear());
         assertEquals(9, datePicker.getMonth());
         assertEquals(10, datePicker.getDayOfMonth());
-
-        // Test onRestoreInstanceState
         assertTrue(datePicker.hasCalledOnRestoreInstanceState());
     }
 
-    private AttributeSet getAttributeSet(int resourceId) {
-        final XmlResourceParser parser = mContext.getResources().getXml(resourceId);
-        try {
-            XmlUtils.beginDocument(parser, "RelativeLayout");
-        } catch (Exception e) {
-            fail("Found unexpected loading process error before invoking generateLayoutParams.");
-        }
-        final AttributeSet attr = Xml.asAttributeSet(parser);
-        assertNotNull(attr);
-        return attr;
-    }
-
-    private MockDatePicker createDatePicker() {
-        MockDatePicker datePicker = new MockDatePicker(mContext,
-                getAttributeSet(R.layout.datepicker_layout));
-        return datePicker;
-    }
-
     private class MockDatePicker extends DatePicker {
         private boolean mCalledOnSaveInstanceState = false;
         private boolean mCalledOnRestoreInstanceState = false;
 
-        public MockDatePicker(Context context, AttributeSet attrs) {
-            super(context, attrs);
+        public MockDatePicker(Context context) {
+            super(context);
         }
 
         @Override
@@ -201,10 +319,4 @@
             return mCalledOnRestoreInstanceState;
         }
     }
-
-    private class MockOnDateChangedListener implements DatePicker.OnDateChangedListener {
-        public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
-
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java b/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java
index a99f56a..120f332 100644
--- a/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java
@@ -16,11 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
@@ -34,10 +29,12 @@
 import android.util.Log;
 import android.util.Xml;
 import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
 import android.widget.DialerFilter;
 import android.widget.EditText;
 import android.widget.RelativeLayout;
+import android.widget.cts.R;
+
+import org.xmlpull.v1.XmlPullParser;
 
 public class DialerFilterTest extends ActivityInstrumentationTestCase2<DialerFilterCtsActivity> {
     private Activity mActivity;
@@ -53,12 +50,7 @@
         super.setUp();
 
         mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
         mInstrumentation = getInstrumentation();
 
         mDialerFilter = (DialerFilter) mActivity.findViewById(R.id.dialer_filter);
diff --git a/tests/tests/widget/src/android/widget/cts/DigitalClockCtsActivity.java b/tests/tests/widget/src/android/widget/cts/DigitalClockCtsActivity.java
index d92651e..07c0270 100644
--- a/tests/tests/widget/src/android/widget/cts/DigitalClockCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/DigitalClockCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 /**
  * A minimal application for TextView test.
diff --git a/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java b/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java
index 2bfcc59..cf1b166 100644
--- a/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java
@@ -16,10 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.XmlResourceParser;
@@ -29,8 +25,11 @@
 import android.util.Xml;
 import android.widget.DigitalClock;
 import android.widget.LinearLayout;
+import android.widget.cts.R;
 import android.widget.cts.util.XmlUtils;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
 
diff --git a/tests/tests/widget/src/android/widget/cts/EditTextTest.java b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
index acf5f38..68c3ab3 100644
--- a/tests/tests/widget/src/android/widget/cts/EditTextTest.java
+++ b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.cts;
 
-import org.xmlpull.v1.XmlPullParser;
-
 import android.content.Context;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -28,9 +26,10 @@
 import android.util.Xml;
 import android.widget.EditText;
 import android.widget.TextView.BufferType;
-
 import android.widget.cts.R;
 
+import org.xmlpull.v1.XmlPullParser;
+
 
 public class EditTextTest extends AndroidTestCase {
     private Context mContext;
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java b/tests/tests/widget/src/android/widget/cts/ExpandableList.java
similarity index 67%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java
copy to tests/tests/widget/src/android/widget/cts/ExpandableList.java
index 6312b47..48fa5e9 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableList.java
@@ -14,14 +14,18 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
-public class NonResizeableActivity extends AbstractLifecycleLogActivity {
+import android.widget.ExpandableListAdapter;
 
-     private static final String TAG = NonResizeableActivity.class.getSimpleName();
+public class ExpandableList extends ExpandableListBasic {
+    @Override
+    protected ExpandableListAdapter createAdapter() {
+        return null;
+    }
 
     @Override
-    protected String getTag() {
-        return TAG;
+    protected boolean shouldRegisterItemClickListener() {
+        return false;
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListSimple.java b/tests/tests/widget/src/android/widget/cts/ExpandableListBasic.java
similarity index 68%
rename from tests/tests/widget/src/android/widget/cts/ExpandableListSimple.java
rename to tests/tests/widget/src/android/widget/cts/ExpandableListBasic.java
index f2e87ee7..b314e15 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListSimple.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListBasic.java
@@ -18,26 +18,25 @@
 
 import android.view.Menu;
 import android.view.MenuItem;
-import android.view.MenuItem.OnMenuItemClickListener;
 import android.widget.BaseExpandableListAdapter;
 import android.widget.cts.util.ExpandableListScenario;
 
-public class ExpandableListSimple extends ExpandableListScenario {
-    private static final int[] NUM_CHILDREN = {4, 3, 2, 1, 0};
+public class ExpandableListBasic extends ExpandableListScenario {
+    private static final int[] CHILD_COUNT = {4, 3, 2, 1, 0};
 
     @Override
     protected void init(ExpandableParams params) {
-        params.setNumChildren(NUM_CHILDREN).setItemScreenSizeFactor(0.14);
+        params.setNumChildren(CHILD_COUNT).setItemScreenSizeFactor(0.14);
     }
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        menu.add("Add item").setOnMenuItemClickListener(new OnMenuItemClickListener() {
-            public boolean onMenuItemClick(MenuItem item) {
+        menu.add("Add item").setOnMenuItemClickListener((MenuItem item) -> {
                 mGroups.add(0, new MyGroup(2));
-                ((BaseExpandableListAdapter) mAdapter).notifyDataSetChanged();
+                if (mAdapter != null) {
+                    ((BaseExpandableListAdapter) mAdapter).notifyDataSetChanged();
+                }
                 return true;
-            }
         });
 
         return true;
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListViewBasicTest.java b/tests/tests/widget/src/android/widget/cts/ExpandableListViewBasicTest.java
index dd8d6a2..be3a3f5 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListViewBasicTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListViewBasicTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-
+import android.app.Instrumentation;
 import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -25,39 +25,36 @@
 import android.widget.ExpandableListAdapter;
 import android.widget.ExpandableListView;
 import android.widget.cts.util.ExpandableListScenario;
-import android.widget.cts.util.ListUtil;
 import android.widget.cts.util.ExpandableListScenario.MyGroup;
+import android.widget.cts.util.ListUtil;
 
 import java.util.List;
 
+@MediumTest
 public class ExpandableListViewBasicTest extends
-        ActivityInstrumentationTestCase2<ExpandableListSimple> {
+        ActivityInstrumentationTestCase2<ExpandableListBasic> {
+    private Instrumentation mInstrumentation;
     private ExpandableListScenario mActivity;
     private ExpandableListView mExpandableListView;
     private ExpandableListAdapter mAdapter;
     private ListUtil mListUtil;
 
     public ExpandableListViewBasicTest() {
-        super(ExpandableListSimple.class);
+        super(ExpandableListBasic.class);
     }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
 
+        mInstrumentation = getInstrumentation();
         mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
         mExpandableListView = mActivity.getExpandableListView();
         mAdapter = mExpandableListView.getExpandableListAdapter();
         mListUtil = new ListUtil(mExpandableListView, getInstrumentation());
     }
 
-    @MediumTest
     public void testPreconditions() {
         assertNotNull(mActivity);
         assertNotNull(mExpandableListView);
@@ -69,7 +66,7 @@
         assertTrue("Could not find group to expand", groupPos >= 0);
         assertFalse("Group is already expanded", mExpandableListView.isGroupExpanded(groupPos));
         mListUtil.arrowScrollToSelectedPosition(groupPos);
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
         getInstrumentation().waitForIdleSync();
         assertTrue("Group did not expand", mExpandableListView.isGroupExpanded(groupPos));
@@ -77,32 +74,29 @@
         return groupPos;
     }
 
-    @MediumTest
     public void testExpandGroup() {
         expandGroup(-1, true);
     }
 
-    @MediumTest
     public void testCollapseGroup() {
         final int groupPos = expandGroup(-1, true);
 
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertFalse("Group did not collapse", mExpandableListView.isGroupExpanded(groupPos));
     }
 
-    @MediumTest
     public void testExpandedGroupMovement() {
         // Expand the first group
         mListUtil.arrowScrollToSelectedPosition(0);
         sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
         // Ensure it expanded
         assertTrue("Group did not expand", mExpandableListView.isGroupExpanded(0));
 
         // Wait until that's all good
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
         // Make sure it expanded
         assertTrue("Group did not expand", mExpandableListView.isGroupExpanded(0));
@@ -117,12 +111,8 @@
                 mAdapter instanceof BaseExpandableListAdapter);
         final BaseExpandableListAdapter adapter = (BaseExpandableListAdapter) mAdapter;
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                adapter.notifyDataSetChanged();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(adapter::notifyDataSetChanged);
+        mInstrumentation.waitForIdleSync();
 
         // Make sure the right group is expanded
         assertTrue("The expanded state didn't stay with the proper group",
@@ -131,20 +121,17 @@
                 mExpandableListView.isGroupExpanded(0));
     }
 
-    @MediumTest
     public void testContextMenus() {
         ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
         tester.testContextMenus();
     }
 
-    @MediumTest
     public void testConvertionBetweenFlatAndPacked() {
         ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
         tester.testConvertionBetweenFlatAndPackedOnGroups();
         tester.testConvertionBetweenFlatAndPackedOnChildren();
     }
 
-    @MediumTest
     public void testSelectedPosition() {
         ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
         tester.testSelectedPositionOnGroups();
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java b/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
index e773ebf..ca9cc4c 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
@@ -16,43 +16,76 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.mockito.Mockito.*;
 
-
-import org.xmlpull.v1.XmlPullParser;
-
+import android.app.Instrumentation;
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.database.DataSetObserver;
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
-import android.test.AndroidTestCase;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.util.AttributeSet;
 import android.util.Xml;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.AdapterView;
 import android.widget.ExpandableListAdapter;
 import android.widget.ExpandableListView;
 import android.widget.ListAdapter;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ExpandableListView.OnChildClickListener;
-import android.widget.ExpandableListView.OnGroupClickListener;
+import android.widget.TextView;
+import android.widget.cts.util.ExpandableListScenario;
 
-public class ExpandableListViewTest extends AndroidTestCase {
+import org.xmlpull.v1.XmlPullParser;
+
+@MediumTest
+public class ExpandableListViewTest extends ActivityInstrumentationTestCase2<ExpandableList> {
+    private Instrumentation mInstrumentation;
+    private ExpandableListScenario mActivity;
+    private ExpandableListView mExpandableListView;
+
+    public ExpandableListViewTest() {
+        super(ExpandableList.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
+        mExpandableListView = mActivity.getExpandableListView();
+    }
+
     public void testConstructor() {
-        new ExpandableListView(mContext);
+        new ExpandableListView(mActivity);
 
-        new ExpandableListView(mContext, null);
+        new ExpandableListView(mActivity, null);
 
-        new ExpandableListView(mContext, null, 0);
+        new ExpandableListView(mActivity, null, android.R.attr.expandableListViewStyle);
+
+        new ExpandableListView(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_ExpandableListView);
+
+        new ExpandableListView(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_ExpandableListView);
+
+        new ExpandableListView(mActivity, null, 0,
+                android.R.style.Widget_Material_ExpandableListView);
+
+        new ExpandableListView(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_ExpandableListView);
 
         XmlPullParser parser =
-            getContext().getResources().getXml(R.layout.expandablelistview_layout);
+                mActivity.getResources().getXml(R.layout.expandablelistview_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
-        new ExpandableListView(mContext, attrs);
-        new ExpandableListView(mContext, attrs, 0);
+        new ExpandableListView(mActivity, attrs);
+        new ExpandableListView(mActivity, attrs, 0);
 
         try {
             new ExpandableListView(null);
@@ -74,230 +107,292 @@
     }
 
     public void testSetChildDivider() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.scenery);
-        expandableListView.setChildDivider(drawable);
+        Drawable drawable = mActivity.getResources().getDrawable(R.drawable.scenery);
+        mExpandableListView.setChildDivider(drawable);
     }
 
     public void testSetAdapter() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
         try {
-            expandableListView.setAdapter((ListAdapter) null);
+            mExpandableListView.setAdapter((ListAdapter) null);
             fail("setAdapter(ListAdapter) should throw RuntimeException here.");
         } catch (RuntimeException e) {
         }
     }
 
+    @UiThreadTest
     public void testGetAdapter() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        assertNull(expandableListView.getAdapter());
+        assertNull(mExpandableListView.getAdapter());
 
         ExpandableListAdapter expandableAdapter = new MockExpandableListAdapter();
-        expandableListView.setAdapter(expandableAdapter);
-        assertNotNull(expandableListView.getAdapter());
+        mExpandableListView.setAdapter(expandableAdapter);
+        assertNotNull(mExpandableListView.getAdapter());
     }
 
+    @UiThreadTest
     public void testAccessExpandableListAdapter() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
         ExpandableListAdapter expandableAdapter = new MockExpandableListAdapter();
 
-        assertNull(expandableListView.getExpandableListAdapter());
-        expandableListView.setAdapter(expandableAdapter);
-        assertSame(expandableAdapter, expandableListView.getExpandableListAdapter());
+        assertNull(mExpandableListView.getExpandableListAdapter());
+        mExpandableListView.setAdapter(expandableAdapter);
+        assertSame(expandableAdapter, mExpandableListView.getExpandableListAdapter());
     }
 
+    @UiThreadTest
     public void testPerformItemClick() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
+        assertFalse(mExpandableListView.performItemClick(null, 100, 99));
 
-        assertFalse(expandableListView.performItemClick(null, 100, 99));
-
-        MockOnItemClickListener onClickListener = new MockOnItemClickListener();
-        expandableListView.setOnItemClickListener(onClickListener);
-        assertTrue(expandableListView.performItemClick(null, 100, 99));
+        ExpandableListView.OnItemClickListener mockOnItemClickListener =
+                mock(ExpandableListView.OnItemClickListener.class);
+        mExpandableListView.setOnItemClickListener(mockOnItemClickListener);
+        assertTrue(mExpandableListView.performItemClick(null, 100, 99));
+        verify(mockOnItemClickListener, times(1)).onItemClick(eq(mExpandableListView),
+                any(View.class), eq(100), eq(99L));
     }
 
     public void testSetOnItemClickListener() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        MockOnItemClickListener listener = new MockOnItemClickListener();
+        ExpandableListView.OnItemClickListener mockOnItemClickListener =
+                mock(ExpandableListView.OnItemClickListener.class);
 
-        assertNull(expandableListView.getOnItemClickListener());
-        expandableListView.setOnItemClickListener(listener);
-        assertSame(listener, expandableListView.getOnItemClickListener());
+        assertNull(mExpandableListView.getOnItemClickListener());
+        mExpandableListView.setOnItemClickListener(mockOnItemClickListener);
+        assertSame(mockOnItemClickListener, mExpandableListView.getOnItemClickListener());
     }
 
+    @UiThreadTest
     public void testExpandGroup() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
         ExpandableListAdapter expandableAdapter = new MockExpandableListAdapter();
-        expandableListView.setAdapter(expandableAdapter);
+        mExpandableListView.setAdapter(expandableAdapter);
 
-        MockOnGroupExpandListener mockOnGroupExpandListener = new MockOnGroupExpandListener();
-        expandableListView.setOnGroupExpandListener(mockOnGroupExpandListener);
+        ExpandableListView.OnGroupExpandListener mockOnGroupExpandListener =
+                mock(ExpandableListView.OnGroupExpandListener.class);
+        mExpandableListView.setOnGroupExpandListener(mockOnGroupExpandListener);
 
-        assertFalse(mockOnGroupExpandListener.hasCalledOnGroupExpand());
-        assertTrue(expandableListView.expandGroup(0));
-        assertTrue(mockOnGroupExpandListener.hasCalledOnGroupExpand());
-        mockOnGroupExpandListener.reset();
-        assertFalse(expandableListView.expandGroup(0));
-        assertTrue(mockOnGroupExpandListener.hasCalledOnGroupExpand());
-        mockOnGroupExpandListener.reset();
-        assertTrue(expandableListView.expandGroup(1));
-        assertTrue(mockOnGroupExpandListener.hasCalledOnGroupExpand());
-        mockOnGroupExpandListener.reset();
-        assertFalse(expandableListView.expandGroup(1));
-        assertTrue(mockOnGroupExpandListener.hasCalledOnGroupExpand());
-        mockOnGroupExpandListener.reset();
+        verifyZeroInteractions(mockOnGroupExpandListener);
 
-        expandableListView.setAdapter((ExpandableListAdapter) null);
+        assertTrue(mExpandableListView.expandGroup(0));
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(0);
+        assertTrue(mExpandableListView.isGroupExpanded(0));
+
+        reset(mockOnGroupExpandListener);
+        assertFalse(mExpandableListView.expandGroup(0));
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(0);
+        assertTrue(mExpandableListView.isGroupExpanded(0));
+
+        reset(mockOnGroupExpandListener);
+        assertTrue(mExpandableListView.expandGroup(1));
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(1);
+        assertTrue(mExpandableListView.isGroupExpanded(1));
+
+        reset(mockOnGroupExpandListener);
+        assertFalse(mExpandableListView.expandGroup(1));
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(1);
+        assertTrue(mExpandableListView.isGroupExpanded(1));
+
+        reset(mockOnGroupExpandListener);
+        mExpandableListView.setAdapter((ExpandableListAdapter) null);
         try {
-            expandableListView.expandGroup(0);
+            mExpandableListView.expandGroup(0);
             fail("should throw NullPointerException");
         } catch (NullPointerException e) {
         }
     }
 
+    public void testExpandGroupSmooth() {
+        mInstrumentation.runOnMainSync(
+                () -> mExpandableListView.setAdapter(new MockExpandableListAdapter()));
+
+        ExpandableListView.OnGroupExpandListener mockOnGroupExpandListener =
+                mock(ExpandableListView.OnGroupExpandListener.class);
+        mExpandableListView.setOnGroupExpandListener(mockOnGroupExpandListener);
+
+        verifyZeroInteractions(mockOnGroupExpandListener);
+        mInstrumentation.runOnMainSync(() -> assertTrue(mExpandableListView.expandGroup(0, true)));
+        mInstrumentation.waitForIdleSync();
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(0);
+        assertTrue(mExpandableListView.isGroupExpanded(0));
+
+        reset(mockOnGroupExpandListener);
+        mInstrumentation.runOnMainSync(() -> assertFalse(mExpandableListView.expandGroup(0, true)));
+        mInstrumentation.waitForIdleSync();
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(0);
+        assertTrue(mExpandableListView.isGroupExpanded(0));
+
+        reset(mockOnGroupExpandListener);
+        mInstrumentation.runOnMainSync(() -> assertTrue(mExpandableListView.expandGroup(1, true)));
+        mInstrumentation.waitForIdleSync();
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(1);
+        assertTrue(mExpandableListView.isGroupExpanded(1));
+
+        reset(mockOnGroupExpandListener);
+        mInstrumentation.runOnMainSync(() -> assertFalse(mExpandableListView.expandGroup(1, true)));
+        mInstrumentation.waitForIdleSync();
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(1);
+        assertTrue(mExpandableListView.isGroupExpanded(1));
+
+        reset(mockOnGroupExpandListener);
+        mInstrumentation.runOnMainSync(() -> {
+            mExpandableListView.setAdapter((ExpandableListAdapter) null);
+            try {
+                mExpandableListView.expandGroup(0);
+                fail("should throw NullPointerException");
+            } catch (NullPointerException e) {
+            }
+        });
+    }
+
+    @UiThreadTest
     public void testCollapseGroup() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
         ExpandableListAdapter expandableAdapter = new MockExpandableListAdapter();
-        expandableListView.setAdapter(expandableAdapter);
+        mExpandableListView.setAdapter(expandableAdapter);
 
-        MockOnGroupCollapseListener mockOnGroupCollapseListener =
-            new MockOnGroupCollapseListener();
-        expandableListView.setOnGroupCollapseListener(mockOnGroupCollapseListener);
+        ExpandableListView.OnGroupCollapseListener mockOnGroupCollapseListener =
+                mock(ExpandableListView.OnGroupCollapseListener.class);
+        mExpandableListView.setOnGroupCollapseListener(mockOnGroupCollapseListener);
 
-        assertFalse(mockOnGroupCollapseListener.hasCalledOnGroupCollapse());
-        assertFalse(expandableListView.collapseGroup(0));
-        assertTrue(mockOnGroupCollapseListener.hasCalledOnGroupCollapse());
-        mockOnGroupCollapseListener.reset();
+        verifyZeroInteractions(mockOnGroupCollapseListener);
+        assertFalse(mExpandableListView.collapseGroup(0));
+        verify(mockOnGroupCollapseListener, times(1)).onGroupCollapse(0);
+        assertFalse(mExpandableListView.isGroupExpanded(0));
 
-        expandableListView.expandGroup(0);
-        assertTrue(expandableListView.collapseGroup(0));
-        assertTrue(mockOnGroupCollapseListener.hasCalledOnGroupCollapse());
-        mockOnGroupCollapseListener.reset();
-        assertFalse(expandableListView.collapseGroup(1));
-        assertTrue(mockOnGroupCollapseListener.hasCalledOnGroupCollapse());
-        mockOnGroupCollapseListener.reset();
+        reset(mockOnGroupCollapseListener);
+        mExpandableListView.expandGroup(0);
+        assertTrue(mExpandableListView.collapseGroup(0));
+        verify(mockOnGroupCollapseListener, times(1)).onGroupCollapse(0);
+        assertFalse(mExpandableListView.isGroupExpanded(0));
 
-        expandableListView.setAdapter((ExpandableListAdapter) null);
+        reset(mockOnGroupCollapseListener);
+        assertFalse(mExpandableListView.collapseGroup(1));
+        verify(mockOnGroupCollapseListener, times(1)).onGroupCollapse(1);
+        assertFalse(mExpandableListView.isGroupExpanded(1));
+
+        reset(mockOnGroupCollapseListener);
+        mExpandableListView.setAdapter((ExpandableListAdapter) null);
         try {
-            expandableListView.collapseGroup(0);
+            mExpandableListView.collapseGroup(0);
             fail("should throw NullPointerException");
         } catch (NullPointerException e) {
         }
     }
 
+    @UiThreadTest
     public void testSetOnGroupClickListener() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setAdapter(new MockExpandableListAdapter());
-        MockOnGroupClickListener listener = new MockOnGroupClickListener();
+        mExpandableListView.setAdapter(new MockExpandableListAdapter());
 
-        expandableListView.setOnGroupClickListener(listener);
-        assertFalse(listener.hasCalledOnGroupClick());
-        expandableListView.performItemClick(null, 0, 0);
-        assertTrue(listener.hasCalledOnGroupClick());
+        ExpandableListView.OnGroupClickListener mockOnGroupClickListener =
+                mock(ExpandableListView.OnGroupClickListener.class);
+
+        mExpandableListView.setOnGroupClickListener(mockOnGroupClickListener);
+        verifyZeroInteractions(mockOnGroupClickListener);
+
+        mExpandableListView.performItemClick(null, 0, 0);
+        verify(mockOnGroupClickListener, times(1)).onGroupClick(eq(mExpandableListView),
+                any(View.class), eq(0), eq(0L));
     }
 
+    @UiThreadTest
     public void testSetOnChildClickListener() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setAdapter(new MockExpandableListAdapter());
-        MockOnChildClickListener listener = new MockOnChildClickListener();
+        mExpandableListView.setAdapter(new MockExpandableListAdapter());
 
-        expandableListView.setOnChildClickListener(listener);
-        assertFalse(listener.hasCalledOnChildClick());
+        ExpandableListView.OnChildClickListener mockOnChildClickListener =
+                mock(ExpandableListView.OnChildClickListener.class);
+
+        mExpandableListView.setOnChildClickListener(mockOnChildClickListener);
+        verifyZeroInteractions(mockOnChildClickListener);
+
         // first let the list expand
-        expandableListView.expandGroup(0);
+        mExpandableListView.expandGroup(0);
         // click on the child list of the first group
-        expandableListView.performItemClick(null, 1, 0);
-        assertTrue(listener.hasCalledOnChildClick());
+        mExpandableListView.performItemClick(null, 1, 0);
+        verify(mockOnChildClickListener, times(1)).onChildClick(eq(mExpandableListView),
+                any(View.class), eq(0), eq(0), eq(0L));
     }
 
+    @UiThreadTest
     public void testGetExpandableListPosition() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setAdapter(new MockExpandableListAdapter());
+        mExpandableListView.setAdapter(new MockExpandableListAdapter());
 
-        assertEquals(0, expandableListView.getExpandableListPosition(0));
+        assertEquals(0, mExpandableListView.getExpandableListPosition(0));
 
         // Group 0 is not expanded, position 1 is invalid
         assertEquals(ExpandableListView.PACKED_POSITION_VALUE_NULL,
-                expandableListView.getExpandableListPosition(1));
+                mExpandableListView.getExpandableListPosition(1));
 
         // Position 1 becomes valid when group 0 is expanded
-        expandableListView.expandGroup(0);
+        mExpandableListView.expandGroup(0);
         assertEquals(ExpandableListView.getPackedPositionForChild(0, 0),
-                expandableListView.getExpandableListPosition(1));
+                mExpandableListView.getExpandableListPosition(1));
 
         // Position 2 is still invalid (only one child).
         assertEquals(ExpandableListView.PACKED_POSITION_VALUE_NULL,
-                expandableListView.getExpandableListPosition(2));
+                mExpandableListView.getExpandableListPosition(2));
     }
 
+    @UiThreadTest
     public void testGetFlatListPosition() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setAdapter(new MockExpandableListAdapter());
+        mExpandableListView.setAdapter(new MockExpandableListAdapter());
 
         try {
-            expandableListView.getFlatListPosition(ExpandableListView.PACKED_POSITION_VALUE_NULL);
+            mExpandableListView.getFlatListPosition(ExpandableListView.PACKED_POSITION_VALUE_NULL);
         } catch (NullPointerException e) {
         }
-        assertEquals(0, expandableListView.getFlatListPosition(
+        assertEquals(0, mExpandableListView.getFlatListPosition(
                 ExpandableListView.PACKED_POSITION_TYPE_CHILD<<32));
         // 0x8000000100000000L means this is a child and group position is 1.
-        assertEquals(1, expandableListView.getFlatListPosition(0x8000000100000000L));
+        assertEquals(1, mExpandableListView.getFlatListPosition(0x8000000100000000L));
     }
 
+    @UiThreadTest
     public void testGetSelectedPosition() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-
         assertEquals(ExpandableListView.PACKED_POSITION_VALUE_NULL,
-                expandableListView.getSelectedPosition());
+                mExpandableListView.getSelectedPosition());
 
-        expandableListView.setAdapter(new MockExpandableListAdapter());
+        mExpandableListView.setAdapter(new MockExpandableListAdapter());
 
-        expandableListView.setSelectedGroup(0);
-        assertEquals(0, expandableListView.getSelectedPosition());
+        mExpandableListView.setSelectedGroup(0);
+        assertEquals(0, mExpandableListView.getSelectedPosition());
 
-        expandableListView.setSelectedGroup(1);
-        assertEquals(0, expandableListView.getSelectedPosition());
+        mExpandableListView.setSelectedGroup(1);
+        assertEquals(0, mExpandableListView.getSelectedPosition());
     }
 
+    @UiThreadTest
     public void testGetSelectedId() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
+        assertEquals(-1, mExpandableListView.getSelectedId());
+        mExpandableListView.setAdapter(new MockExpandableListAdapter());
 
-        assertEquals(-1, expandableListView.getSelectedId());
-        expandableListView.setAdapter(new MockExpandableListAdapter());
+        mExpandableListView.setSelectedGroup(0);
+        assertEquals(0, mExpandableListView.getSelectedId());
 
-        expandableListView.setSelectedGroup(0);
-        assertEquals(0, expandableListView.getSelectedId());
-
-        expandableListView.setSelectedGroup(1);
-        assertEquals(0, expandableListView.getSelectedId());
+        mExpandableListView.setSelectedGroup(1);
+        assertEquals(0, mExpandableListView.getSelectedId());
     }
 
+    @UiThreadTest
     public void testSetSelectedGroup() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setAdapter(new MockExpandableListAdapter());
+        mExpandableListView.setAdapter(new MockExpandableListAdapter());
 
-        expandableListView.setSelectedGroup(0);
-        assertEquals(0, expandableListView.getSelectedPosition());
+        mExpandableListView.setSelectedGroup(0);
+        assertEquals(0, mExpandableListView.getSelectedPosition());
 
-        expandableListView.setSelectedGroup(1);
-        assertEquals(0, expandableListView.getSelectedPosition());
+        mExpandableListView.setSelectedGroup(1);
+        assertEquals(0, mExpandableListView.getSelectedPosition());
     }
 
+    @UiThreadTest
     public void testSetSelectedChild() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setAdapter(new MockExpandableListAdapter());
+        mExpandableListView.setAdapter(new MockExpandableListAdapter());
 
-        assertTrue(expandableListView.setSelectedChild(0, 0, false));
-        assertTrue(expandableListView.setSelectedChild(0, 1, true));
+        assertTrue(mExpandableListView.setSelectedChild(0, 0, false));
+        assertTrue(mExpandableListView.setSelectedChild(0, 1, true));
     }
 
+    @UiThreadTest
     public void testIsGroupExpanded() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setAdapter(new MockExpandableListAdapter());
+        mExpandableListView.setAdapter(new MockExpandableListAdapter());
 
-        expandableListView.expandGroup(1);
-        assertFalse(expandableListView.isGroupExpanded(0));
-        assertTrue(expandableListView.isGroupExpanded(1));
+        mExpandableListView.expandGroup(1);
+        assertFalse(mExpandableListView.isGroupExpanded(0));
+        assertTrue(mExpandableListView.isGroupExpanded(1));
     }
 
     public void testGetPackedPositionType() {
@@ -356,31 +451,35 @@
     }
 
     public void testSetChildIndicator() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setChildIndicator(null);
+        mExpandableListView.setChildIndicator(null);
     }
 
     public void testSetChildIndicatorBounds() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setChildIndicatorBounds(10, 10);
+        mExpandableListView.setChildIndicatorBounds(10, 20);
+    }
+
+    public void testSetChildIndicatorBoundsRelative() {
+        mExpandableListView.setChildIndicatorBoundsRelative(10, 20);
     }
 
     public void testSetGroupIndicator() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
         Drawable drawable = new BitmapDrawable();
-        expandableListView.setGroupIndicator(drawable);
+        mExpandableListView.setGroupIndicator(drawable);
     }
 
     public void testSetIndicatorBounds() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setIndicatorBounds(10,10);
+        mExpandableListView.setIndicatorBounds(10, 30);
+    }
+
+    public void testSetIndicatorBoundsRelative() {
+        mExpandableListView.setIndicatorBoundsRelative(10, 30);
     }
 
     public void testOnSaveInstanceState() {
-        ExpandableListView src = new ExpandableListView(mContext);
+        ExpandableListView src = new ExpandableListView(mActivity);
         Parcelable p1 = src.onSaveInstanceState();
 
-        ExpandableListView dest = new ExpandableListView(mContext);
+        ExpandableListView dest = new ExpandableListView(mActivity);
         dest.onRestoreInstanceState(p1);
         Parcelable p2 = dest.onSaveInstanceState();
 
@@ -389,11 +488,17 @@
     }
 
     public void testDispatchDraw() {
-        MockExpandableListView expandableListView = new MockExpandableListView(mContext);
+        MockExpandableListView expandableListView = new MockExpandableListView(mActivity);
         expandableListView.dispatchDraw(new Canvas());
     }
 
     private class MockExpandableListAdapter implements ExpandableListAdapter {
+        private final LayoutInflater mLayoutInflater;
+
+        public MockExpandableListAdapter() {
+            mLayoutInflater = LayoutInflater.from(mActivity);
+        }
+
         public void registerDataSetObserver(DataSetObserver observer) {
         }
 
@@ -443,12 +548,24 @@
 
         public View getGroupView(int groupPosition, boolean isExpanded,
                 View convertView, ViewGroup parent) {
-            return null;
+            TextView result = (TextView) convertView;
+            if (result == null) {
+                result = (TextView) mLayoutInflater.inflate(
+                        R.layout.expandablelistview_group, parent, false);
+            }
+            result.setText("Group " + groupPosition);
+            return result;
         }
 
         public View getChildView(int groupPosition, int childPosition,
                 boolean isLastChild, View convertView, ViewGroup parent) {
-            return null;
+            TextView result = (TextView) convertView;
+            if (result == null) {
+                result = (TextView) mLayoutInflater.inflate(
+                        R.layout.expandablelistview_child, parent, false);
+            }
+            result.setText("Child " + childPosition);
+            return result;
         }
 
         public boolean isChildSelectable(int groupPosition, int childPosition) {
@@ -478,72 +595,6 @@
         }
     }
 
-    private class MockOnGroupExpandListener implements ExpandableListView.OnGroupExpandListener {
-        private boolean mCalledOnGroupExpand = false;
-
-        public void onGroupExpand(int groupPosition) {
-            mCalledOnGroupExpand = true;
-        }
-
-        public boolean hasCalledOnGroupExpand() {
-            return mCalledOnGroupExpand;
-        }
-
-        public void reset() {
-            mCalledOnGroupExpand = false;
-        }
-    }
-
-    private class MockOnGroupCollapseListener implements
-            ExpandableListView.OnGroupCollapseListener {
-        private boolean mCalledOnGroupCollapse = false;
-
-        public void onGroupCollapse(int groupPosition) {
-            mCalledOnGroupCollapse = true;
-        }
-
-        public boolean hasCalledOnGroupCollapse() {
-            return mCalledOnGroupCollapse;
-        }
-
-        public void reset() {
-            mCalledOnGroupCollapse = false;
-        }
-    }
-
-    private class MockOnItemClickListener implements OnItemClickListener {
-        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        }
-    }
-
-    private class MockOnGroupClickListener implements OnGroupClickListener {
-        private boolean mCalledOnGroupClick = false;
-
-        public boolean onGroupClick(ExpandableListView parent, View v,
-                int groupPosition, long id) {
-            mCalledOnGroupClick = true;
-            return true;
-        }
-
-        public boolean hasCalledOnGroupClick() {
-            return mCalledOnGroupClick;
-        }
-    }
-
-    private class MockOnChildClickListener implements OnChildClickListener {
-        private boolean mCalledOnChildClick = false;
-
-        public boolean onChildClick(ExpandableListView parent, View v,
-                int groupPosition, int childPosition, long id) {
-            mCalledOnChildClick = true;
-            return true;
-        }
-
-        public boolean hasCalledOnChildClick() {
-            return mCalledOnChildClick;
-        }
-    }
-
     private class MockExpandableListView extends ExpandableListView {
         public MockExpandableListView(Context context) {
             super(context);
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListViewWithHeadersTest.java b/tests/tests/widget/src/android/widget/cts/ExpandableListViewWithHeadersTest.java
index 7f4715f..91ce4cd 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListViewWithHeadersTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListViewWithHeadersTest.java
@@ -39,12 +39,7 @@
         super.setUp();
 
         final ExpandableListWithHeaders activity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return activity.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(activity::hasWindowFocus);
         mExpandableListView = activity.getExpandableListView();
         mListUtil = new ListUtil(mExpandableListView, getInstrumentation());
     }
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListView_ExpandableListContextMenuInfoTest.java b/tests/tests/widget/src/android/widget/cts/ExpandableListView_ExpandableListContextMenuInfoTest.java
index bf5a23f..f62dcd2 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListView_ExpandableListContextMenuInfoTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListView_ExpandableListContextMenuInfoTest.java
@@ -18,10 +18,9 @@
 package android.widget.cts;
 
 import android.test.AndroidTestCase;
-import android.view.View;
 import android.widget.ExpandableListView;
-import android.widget.ListView;
 import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
+import android.widget.ListView;
 
 /**
  * Test {@link ExpandableListContextMenuInfo}.
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListWithHeaders.java b/tests/tests/widget/src/android/widget/cts/ExpandableListWithHeaders.java
index 259d443..17e8a59 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListWithHeaders.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListWithHeaders.java
@@ -22,14 +22,14 @@
 import android.widget.cts.util.ExpandableListScenario;
 
 public class ExpandableListWithHeaders extends ExpandableListScenario {
-    private static final int[] sNumChildren = {1, 4, 3, 2, 6};
-    private static final int sNumOfHeadersAndFooters = 12;
+    private static final int[] CHILD_COUNT = {1, 4, 3, 2, 6};
+    private static final int HEADER_FOOTER_COUNT = 12;
 
     @Override
     protected void init(ExpandableParams params) {
         params.setStackFromBottom(false)
                 .setStartingSelectionPosition(-1)
-                .setNumChildren(sNumChildren)
+                .setNumChildren(CHILD_COUNT)
                 .setItemScreenSizeFactor(0.14)
                 .setConnectAdapter(false);
     }
@@ -41,13 +41,13 @@
         final ExpandableListView expandableListView = getExpandableListView();
         expandableListView.setItemsCanFocus(true);
 
-        for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
+        for (int i = 0; i < HEADER_FOOTER_COUNT; i++) {
             Button header = new Button(this);
             header.setText("Header View");
             expandableListView.addHeaderView(header);
         }
 
-        for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
+        for (int i = 0; i < HEADER_FOOTER_COUNT; i++) {
             Button footer = new Button(this);
             footer.setText("Footer View");
             expandableListView.addFooterView(footer);
@@ -61,6 +61,6 @@
      * @return The number of headers (and the same number of footers)
      */
     public int getNumOfHeadersAndFooters() {
-        return sNumOfHeadersAndFooters;
+        return HEADER_FOOTER_COUNT;
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/FilterTest.java b/tests/tests/widget/src/android/widget/cts/FilterTest.java
index 7a1d111..97d75f4 100644
--- a/tests/tests/widget/src/android/widget/cts/FilterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FilterTest.java
@@ -16,14 +16,20 @@
 
 package android.widget.cts;
 
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.*;
 
 import android.cts.util.PollingCheck;
-import android.cts.util.ReadElf;
 import android.cts.util.TestThread;
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
 import android.widget.Filter;
-import android.widget.Filter.FilterListener;
+
+import org.junit.Assert;
+import org.mockito.invocation.InvocationOnMock;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 public class FilterTest extends ActivityInstrumentationTestCase2<CtsActivity> {
     private static final long TIME_OUT = 10000;
@@ -66,26 +72,22 @@
         });
         getInstrumentation().waitForIdleSync();
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mMockFilter.hadPerformedFiltering();
-            }
-        }.run();
+        PollingCheck.waitFor(TIME_OUT, mMockFilter::hadPerformedFiltering);
         assertEquals(TEST_CONSTRAINT, mMockFilter.getPerformFilteringConstraint());
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mMockFilter.hadPublishedResults();
-            }
-        }.run();
+        PollingCheck.waitFor(TIME_OUT, mMockFilter::hadPublishedResults);
         assertEquals(TEST_CONSTRAINT, mMockFilter.getPublishResultsConstraint());
         assertSame(mMockFilter.getExpectResults(), mMockFilter.getResults());
     }
 
     public void testFilter2() {
-        final MockFilterListener mockFilterListener = new MockFilterListener();
+        final CountDownLatch countDownLatch = new CountDownLatch(1);
+        final Filter.FilterListener mockFilterListener = mock(Filter.FilterListener.class);
+        doAnswer((InvocationOnMock invocation) -> {
+            countDownLatch.countDown();
+            return null;
+        }).when(mockFilterListener).onFilterComplete(anyInt());
+
         getActivity().runOnUiThread(new Runnable() {
             public void run() {
                 mMockFilter = new MockFilter();
@@ -94,29 +96,18 @@
         });
         getInstrumentation().waitForIdleSync();
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mMockFilter.hadPerformedFiltering();
-            }
-        }.run();
+        PollingCheck.waitFor(TIME_OUT, mMockFilter::hadPerformedFiltering);
         assertEquals(TEST_CONSTRAINT, mMockFilter.getPerformFilteringConstraint());
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mMockFilter.hadPublishedResults();
-            }
-        }.run();
+        PollingCheck.waitFor(TIME_OUT, mMockFilter::hadPublishedResults);
         assertEquals(TEST_CONSTRAINT, mMockFilter.getPublishResultsConstraint());
         assertSame(mMockFilter.getExpectResults(), mMockFilter.getResults());
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mockFilterListener.hasCalledOnFilterComplete();
-            }
-        }.run();
+        try {
+            countDownLatch.await(TIME_OUT, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException ie) {
+            Assert.fail(ie.toString());
+        }
     }
 
     private static class MockFilter extends Filter {
@@ -185,16 +176,4 @@
             }
         }
     }
-
-    private static class MockFilterListener implements FilterListener {
-        private boolean mCalledOnFilterComplete = false;
-
-        public void onFilterComplete(int count) {
-            mCalledOnFilterComplete = true;
-        }
-
-        public boolean hasCalledOnFilterComplete() {
-            return mCalledOnFilterComplete;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java b/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
index 4309dbb..ff399fc 100644
--- a/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
@@ -16,8 +16,8 @@
 
 package android.widget.cts;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
 import android.app.Instrumentation;
@@ -25,15 +25,15 @@
 import android.content.res.ColorStateList;
 import android.cts.util.PollingCheck;
 import android.cts.util.WidgetTestUtils;
-import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.ColorFilter;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.Gravity;
@@ -44,11 +44,14 @@
 import android.widget.FrameLayout.LayoutParams;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.widget.cts.R;
-import android.widget.cts.util.ViewTestUtils;
+
+import org.mockito.ArgumentCaptor;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 
+@SmallTest
 public class FrameLayoutTest extends ActivityInstrumentationTestCase2<FrameLayoutCtsActivity> {
     private Activity mActivity;
     private Instrumentation mInstrumentation;
@@ -87,30 +90,25 @@
         assertTrue(mFrameLayout.getWidth() > foreground.getIntrinsicWidth());
         assertNull(mFrameLayout.getForeground());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout,
                 () -> mFrameLayout.setForeground(foreground));
         assertSame(foreground, mFrameLayout.getForeground());
         // check the default gravity FILL, it completely fills its container
         assertTrue(foreground.isVisible());
         final Rect rect = foreground.getBounds();
         // foreground has been stretched
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mFrameLayout.getHeight() == rect.bottom - rect.top;
-            }
-        }.run();
+        PollingCheck.waitFor(() -> mFrameLayout.getHeight() == rect.bottom - rect.top);
         assertEquals(mFrameLayout.getWidth(), rect.right - rect.left);
 
         // should get a new foreground again, because former foreground has been stretched
         final BitmapDrawable newForeground =
-                (BitmapDrawable) mActivity.getResources().getDrawable(R.drawable.size_48x48);
+                (BitmapDrawable) mActivity.getDrawable(R.drawable.size_48x48);
         compareScaledPixels(48, newForeground.getIntrinsicHeight());
         compareScaledPixels(48, newForeground.getIntrinsicWidth());
         assertTrue(mFrameLayout.getHeight() > newForeground.getIntrinsicHeight());
         assertTrue(mFrameLayout.getWidth() > foreground.getIntrinsicWidth());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout, () -> {
             mFrameLayout.setForeground(newForeground);
             mFrameLayout.setForegroundGravity(Gravity.CENTER);
         });
@@ -128,7 +126,7 @@
         final LinearLayout container =
                 (LinearLayout) mActivity.findViewById(R.id.framelayout_container);
         final Drawable foreground = mActivity.getResources().getDrawable(R.drawable.size_48x48);
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout, () -> {
             mFrameLayout.setForeground(foreground);
             mFrameLayout.setForegroundGravity(Gravity.CENTER);
         });
@@ -136,7 +134,7 @@
         Region region = new Region(foreground.getBounds());
         assertTrue(mFrameLayout.gatherTransparentRegion(region));
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout,
                 () -> container.requestTransparentRegion(mFrameLayout));
         mInstrumentation.waitForIdleSync();
         region = new Region(foreground.getBounds());
@@ -156,7 +154,7 @@
         assertEquals(textView.getMeasuredWidth(), frameLayout.getMeasuredWidth());
 
         // measureAll is false and text view is GONE, text view will NOT be measured
-        mActivity.runOnUiThread(() -> {
+        mInstrumentation.runOnMainSync(() -> {
             textView.setVisibility(View.GONE);
             frameLayout.requestLayout();
         });
@@ -169,11 +167,12 @@
         assertEquals(button.getMeasuredWidth(), frameLayout.getMeasuredWidth());
 
         // measureAll is true and text view is GONE, text view will be measured
-        mActivity.runOnUiThread(() -> {
+        mInstrumentation.runOnMainSync(() -> {
             frameLayout.setMeasureAllChildren(true);
             frameLayout.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
+        assertTrue(frameLayout.getMeasureAllChildren());
         assertTrue(frameLayout.getConsiderGoneChildrenWhenMeasuring());
         assertEquals(textView.getMeasuredHeight(), frameLayout.getMeasuredHeight());
         assertEquals(textView.getMeasuredWidth(), frameLayout.getMeasuredWidth());
@@ -285,21 +284,25 @@
         assertEquals("Foreground tint mode inflated correctly",
                 PorterDuff.Mode.SRC_OVER, inflatedView.getForegroundTintMode());
 
-        MockDrawable foreground = new MockDrawable();
+        final Drawable foreground = spy(new ColorDrawable());
         FrameLayout view = new FrameLayout(mActivity);
 
         view.setForeground(foreground);
-        assertFalse("No foreground tint applied by default", foreground.hasCalledSetTint());
+        verify(foreground, never()).setTintList(any(ColorStateList.class));
 
-        view.setForegroundTintList(ColorStateList.valueOf(Color.WHITE));
-        assertTrue("Foreground tint applied when setForegroundTintList() called after setForeground()",
-                foreground.hasCalledSetTint());
+        view.setForegroundTintList(ColorStateList.valueOf(Color.RED));
+        final ArgumentCaptor<ColorStateList> colorStateListCaptor =
+                ArgumentCaptor.forClass(ColorStateList.class);
+        verify(foreground, times(1)).setTintList(colorStateListCaptor.capture());
+        assertEquals(1, colorStateListCaptor.getValue().getColors().length);
+        assertEquals(Color.RED, colorStateListCaptor.getValue().getColors()[0]);
 
-        foreground.reset();
+        reset(foreground);
         view.setForeground(null);
         view.setForeground(foreground);
-        assertTrue("Foreground tint applied when setForegroundTintList() called before setForeground()",
-                foreground.hasCalledSetTint());
+        verify(foreground, times(1)).setTintList(colorStateListCaptor.capture());
+        assertEquals(1, colorStateListCaptor.getValue().getColors().length);
+        assertEquals(Color.RED, colorStateListCaptor.getValue().getColors()[0]);
     }
 
     private static void assertCenterAligned(View container, Drawable drawable) {
@@ -319,38 +322,6 @@
         return Xml.asAttributeSet(parser);
     }
 
-    private static class MockDrawable extends Drawable {
-        private boolean mCalledSetTint = false;
-
-        @Override
-        public void draw(Canvas canvas) {}
-
-        @Override
-        public void setAlpha(int alpha) {}
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {}
-
-        @Override
-        public void setTintList(ColorStateList tint) {
-            super.setTintList(tint);
-            mCalledSetTint = true;
-        }
-
-        @Override
-        public int getOpacity() {
-            return 0;
-        }
-
-        public boolean hasCalledSetTint() {
-            return mCalledSetTint;
-        }
-
-        public void reset() {
-            mCalledSetTint = false;
-        }
-    }
-
     private static class MyFrameLayout extends FrameLayout {
         public MyFrameLayout(Context context) {
             super(context);
diff --git a/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
index 5774b53..1b8f253 100644
--- a/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
@@ -16,21 +16,19 @@
 
 package android.widget.cts;
 
-import android.view.Gravity;
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.cts.util.WidgetTestUtils;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.Xml;
+import android.view.Gravity;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.FrameLayout;
 import android.widget.FrameLayout.LayoutParams;
+import android.widget.cts.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 
diff --git a/tests/tests/widget/src/android/widget/cts/GalleryCtsActivity.java b/tests/tests/widget/src/android/widget/cts/GalleryCtsActivity.java
index 8039f47..8b80a96 100644
--- a/tests/tests/widget/src/android/widget/cts/GalleryCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/GalleryCtsActivity.java
@@ -16,8 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
@@ -26,6 +24,7 @@
 import android.widget.BaseAdapter;
 import android.widget.Gallery;
 import android.widget.ImageView;
+import android.widget.cts.R;
 
 /**
  * A minimal application for {@link Gallery} test.
diff --git a/tests/tests/widget/src/android/widget/cts/GalleryTest.java b/tests/tests/widget/src/android/widget/cts/GalleryTest.java
index dd39461..5394319 100644
--- a/tests/tests/widget/src/android/widget/cts/GalleryTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GalleryTest.java
@@ -16,40 +16,29 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.cts.util.WidgetTestUtils;
-import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.test.ViewAsserts;
 import android.util.AttributeSet;
 import android.util.Xml;
-import android.view.ContextMenu;
 import android.view.Gravity;
 import android.view.KeyEvent;
-import android.view.MenuItem;
-import android.view.SubMenu;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.View.OnCreateContextMenuListener;
 import android.view.ViewGroup.LayoutParams;
 import android.view.animation.Transformation;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.Gallery;
 import android.widget.ImageView;
-import android.widget.AdapterView.OnItemSelectedListener;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 
@@ -348,37 +337,4 @@
                 R.drawable.testimage,
         };
     }
-
-    private static class MockOnItemSelectedListener implements OnItemSelectedListener {
-        private boolean mIsItemSelected;
-        private boolean mNothingSelected;
-        private int mItemSelectedCalledCount;
-
-        public boolean isItemSelected() {
-            return mIsItemSelected;
-        }
-
-        public boolean hasNothingSelected() {
-            return mNothingSelected;
-        }
-
-        public int getItemSelectedCalledCount() {
-            return mItemSelectedCalledCount;
-        }
-
-        public void reset() {
-            mIsItemSelected = false;
-            mNothingSelected = true;
-            mItemSelectedCalledCount = 0;
-        }
-
-        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-            mIsItemSelected = true;
-            mItemSelectedCalledCount++;
-        }
-
-        public void onNothingSelected(AdapterView<?> parent) {
-            mNothingSelected = true;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java
index eacb676..daa40b4 100644
--- a/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java
@@ -16,15 +16,13 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.content.res.XmlResourceParser;
 import android.cts.util.WidgetTestUtils;
 import android.test.AndroidTestCase;
 import android.widget.Gallery.LayoutParams;
+import android.widget.cts.R;
+
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 
diff --git a/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java b/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java
index 65e86b3..83dcfd0 100644
--- a/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java
@@ -16,6 +16,8 @@
 
 package android.widget.cts;
 
+import static android.widget.GridLayout.spec;
+
 import android.content.Context;
 import android.test.ActivityInstrumentationTestCase;
 import android.util.AttributeSet;
@@ -28,10 +30,8 @@
 import android.widget.GridLayout;
 import android.widget.TextView;
 import android.widget.cts.R;
-import org.xmlpull.v1.XmlPullParser;
 
-import static android.view.ViewGroup.LAYOUT_MODE_OPTICAL_BOUNDS;
-import static android.widget.GridLayout.spec;
+import org.xmlpull.v1.XmlPullParser;
 
 /**
  * Test {@link android.widget.GridLayout}.
diff --git a/tests/tests/widget/src/android/widget/cts/GridViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/GridViewCtsActivity.java
index 7b2e7a3..47ad5d8 100644
--- a/tests/tests/widget/src/android/widget/cts/GridViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/GridViewCtsActivity.java
@@ -16,17 +16,16 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.GridView;
 
 /**
  * A minimal application for {@link GridView} test.
  */
 public class GridViewCtsActivity extends Activity {
     /**
-     * Called with the activity is first created.
+     * Called when the activity is first created.
      */
     @Override
     public void onCreate(Bundle savedInstanceState) {
diff --git a/tests/tests/widget/src/android/widget/cts/GridViewTest.java b/tests/tests/widget/src/android/widget/cts/GridViewTest.java
index 7b83416..44b1741 100644
--- a/tests/tests/widget/src/android/widget/cts/GridViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GridViewTest.java
@@ -16,23 +16,23 @@
 
 package android.widget.cts;
 
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.cts.util.PollingCheck;
+import android.cts.util.WidgetTestUtils;
 import android.database.DataSetObservable;
 import android.database.DataSetObserver;
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.TouchUtils;
 import android.test.UiThreadTest;
 import android.test.ViewAsserts;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.Gravity;
@@ -47,12 +47,16 @@
 import android.widget.GridView;
 import android.widget.ImageView;
 import android.widget.ListAdapter;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.cts.util.ViewTestUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test {@link GridView}.
  */
+@SmallTest
 public class GridViewTest extends ActivityInstrumentationTestCase<GridViewCtsActivity> {
     private GridView mGridView;
     private Activity mActivity;
@@ -62,22 +66,15 @@
         super("android.widget.cts", GridViewCtsActivity.class);
     }
 
-    private GridView findGridViewById(int id) {
-        return (GridView) mActivity.findViewById(id);
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mGridView = null;
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
+
         mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+        mGridView = (GridView) mActivity.findViewById(R.id.gridview);
+
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
     }
 
     public void testConstructor() {
@@ -87,6 +84,14 @@
 
         new GridView(mActivity, null, android.R.attr.gridViewStyle);
 
+        new GridView(mActivity, null, 0, android.R.style.Widget_DeviceDefault_GridView);
+
+        new GridView(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Light_GridView);
+
+        new GridView(mActivity, null, 0, android.R.style.Widget_Material_GridView);
+
+        new GridView(mActivity, null, 0, android.R.style.Widget_Material_Light_GridView);
+
         XmlPullParser parser = mActivity.getResources().getXml(R.layout.gridview_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
         new GridView(mActivity, attrs);
@@ -111,8 +116,8 @@
         }
     }
 
+    @UiThreadTest
     public void testAccessAdapter() {
-        mGridView = new GridView(mActivity);
         // set Adapter
         ImageAdapter adapter = new ImageAdapter(mActivity);
         mGridView.setAdapter(adapter);
@@ -122,8 +127,8 @@
         assertNull(mGridView.getAdapter());
     }
 
+    @UiThreadTest
     public void testSetSelection() {
-        mGridView = new GridView(mActivity);
         mGridView.setSelection(0);
         assertEquals(0, mGridView.getSelectedItemPosition());
 
@@ -136,10 +141,10 @@
 
     public void testPressKey() {
         final int NUM_COLUMNS = 3;
-        mGridView = findGridViewById(R.id.gridview);
 
-        MockOnItemClickListener listener = new MockOnItemClickListener();
-        mGridView.setOnItemClickListener(listener);
+        GridView.OnItemClickListener mockItemClickListener =
+                mock(GridView.OnItemClickListener.class);
+        mGridView.setOnItemClickListener(mockItemClickListener);
 
         // this test case can not be ran in UI thread.
         mActivity.runOnUiThread(new Runnable() {
@@ -172,20 +177,19 @@
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
         assertEquals(NUM_COLUMNS, mGridView.getSelectedItemPosition());
 
-        assertFalse(listener.hasOnItemClickCalled());
+        verify(mockItemClickListener, never()).onItemClick(any(AdapterView.class), any(View.class),
+                anyInt(), anyLong());
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
-        assertTrue(listener.hasOnItemClickCalled());
+        verify(mockItemClickListener, times(1)).onItemClick(eq(mGridView), any(View.class),
+                eq(NUM_COLUMNS), eq((long) NUM_COLUMNS));
 
-        listener.reset();
-        assertFalse(listener.hasOnItemClickCalled());
+        reset(mockItemClickListener);
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
-        assertTrue(listener.hasOnItemClickCalled());
+        verify(mockItemClickListener, times(1)).onItemClick(eq(mGridView), any(View.class),
+                eq(NUM_COLUMNS), eq((long) NUM_COLUMNS));
     }
 
     public void testSetGravity() {
-        mGridView = findGridViewById(R.id.gridview);
-
-        View child;
         final int NUM_COLUMNS = 1;
         // this test case can not be ran in UI thread.
         mActivity.runOnUiThread(new Runnable() {
@@ -207,8 +211,8 @@
         });
         mInstrumentation.waitForIdleSync();
 
-        child = mGridView.getChildAt(0); // get the first view.
-        ViewAsserts.assertHorizontalCenterAligned(mGridView, child);
+        assertEquals(Gravity.CENTER_HORIZONTAL, mGridView.getGravity());
+        ViewAsserts.assertHorizontalCenterAligned(mGridView, mGridView.getChildAt(0));
 
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
@@ -219,8 +223,9 @@
         });
         mInstrumentation.waitForIdleSync();
 
-        child = mGridView.getChildAt(0); // get the first view.
-        ViewAsserts.assertLeftAligned(mGridView, child, mGridView.getListPaddingLeft());
+        assertEquals(Gravity.LEFT, mGridView.getGravity());
+        ViewAsserts.assertLeftAligned(mGridView, mGridView.getChildAt(0),
+                mGridView.getListPaddingLeft());
 
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
@@ -231,41 +236,34 @@
         });
         mInstrumentation.waitForIdleSync();
 
-        child = mGridView.getChildAt(0); // get the first view.
-        ViewAsserts.assertRightAligned(mGridView, child, mGridView.getListPaddingRight());
+        assertEquals(Gravity.RIGHT, mGridView.getGravity());
+        ViewAsserts.assertRightAligned(mGridView, mGridView.getChildAt(0),
+                mGridView.getListPaddingRight());
     }
 
-    public void testSetHorizontalSpacing() {
-        testSetHorizontalSpacing(View.LAYOUT_DIRECTION_LTR);
+    public void testAccessHorizontalSpacing() {
+        verifyAccessHorizontalSpacing(View.LAYOUT_DIRECTION_LTR);
     }
 
-    public void testSetHorizontalSpacingRTL() {
-        testSetHorizontalSpacing(View.LAYOUT_DIRECTION_RTL);
+    public void testAccessHorizontalSpacingRTL() {
+        verifyAccessHorizontalSpacing(View.LAYOUT_DIRECTION_RTL);
     }
 
-    public void testSetHorizontalSpacing(final int layoutDir) {
-        mGridView = findGridViewById(R.id.gridview);
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setLayoutDirection(layoutDir);
-            }
-        });
+    private void verifyAccessHorizontalSpacing(final int layoutDir) {
+        mActivity.runOnUiThread(() -> mGridView.setLayoutDirection(layoutDir));
         mGridView.setStretchMode(GridView.NO_STRETCH);
         // Number of columns should be big enough, otherwise the
         // horizontal spacing cannot be correctly verified.
         mGridView.setNumColumns(28);
 
-
-        // this test case can not be ran in UI thread.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setAdapter(new MockGridViewAdapter(3));
-                mGridView.setHorizontalSpacing(0);
-            }
+        mActivity.runOnUiThread(() ->  {
+            mGridView.setAdapter(new MockGridViewAdapter(3));
+            mGridView.setHorizontalSpacing(0);
         });
         mInstrumentation.waitForIdleSync();
 
+        assertEquals(0, mGridView.getRequestedHorizontalSpacing());
+        assertEquals(0, mGridView.getHorizontalSpacing());
         View child0 = mGridView.getChildAt(0);
         View child1 = mGridView.getChildAt(1);
         if (layoutDir == View.LAYOUT_DIRECTION_LTR) {
@@ -274,13 +272,11 @@
             assertEquals(0, child0.getLeft() - child1.getRight());
         }
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setHorizontalSpacing(5);
-            }
-        });
+        mActivity.runOnUiThread(() -> mGridView.setHorizontalSpacing(5));
         mInstrumentation.waitForIdleSync();
 
+        assertEquals(5, mGridView.getRequestedHorizontalSpacing());
+        assertEquals(5, mGridView.getHorizontalSpacing());
         child0 = mGridView.getChildAt(0);
         child1 = mGridView.getChildAt(1);
         if (layoutDir == View.LAYOUT_DIRECTION_LTR) {
@@ -290,36 +286,28 @@
         }
     }
 
-    public void testSetVerticalSpacing() {
-        mGridView = findGridViewById(R.id.gridview);
-
-        // this test case can not be ran in UI thread.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setAdapter(new MockGridViewAdapter(3));
-                mGridView.setVerticalSpacing(0);
-            }
+    public void testAccessVerticalSpacing() {
+        mActivity.runOnUiThread(() -> {
+            mGridView.setAdapter(new MockGridViewAdapter(3));
+            mGridView.setVerticalSpacing(0);
         });
         mInstrumentation.waitForIdleSync();
 
+        assertEquals(0, mGridView.getVerticalSpacing());
         View child0 = mGridView.getChildAt(0);
         View child1 = mGridView.getChildAt(1);
         assertEquals(0, child1.getTop() - child0.getBottom());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setVerticalSpacing(5);
-            }
-        });
+        mActivity.runOnUiThread(() -> mGridView.setVerticalSpacing(5));
         mInstrumentation.waitForIdleSync();
 
+        assertEquals(5, mGridView.getVerticalSpacing());
         child0 = mGridView.getChildAt(0);
         child1 = mGridView.getChildAt(1);
         assertEquals(5, child1.getTop() - child0.getBottom());
     }
 
     public void testAccessStretchMode() {
-        mGridView = findGridViewById(R.id.gridview);
         View child;
 
         final int NUM_COLUMNS = 8;
@@ -417,8 +405,6 @@
     }
 
     public void testSetNumColumns() {
-        mGridView = findGridViewById(R.id.gridview);
-
         // this test case can not be ran in UI thread.
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
@@ -459,13 +445,12 @@
         }
     }
 
+    public void testDefaultNumColumns() {
+        final GridView gridView = new GridView(mActivity);
+        assertEquals(gridView.getNumColumns(), GridView.AUTO_FIT);
+    }
+
     public void testGetNumColumns() {
-        mGridView = new GridView(mActivity);
-
-        assertEquals(mGridView.getNumColumns(), GridView.AUTO_FIT);
-
-        mGridView = findGridViewById(R.id.gridview);
-
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 mGridView.setAdapter(new MockGridViewAdapter(10));
@@ -532,36 +517,33 @@
         // Do not test it. It's implementation detail.
     }
 
-    public void testSetColumnWidth() {
-        mGridView = findGridViewById(R.id.gridview);
-
-        // this test case can not be ran in UI thread.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setAdapter(new MockGridViewAdapter(10));
-                mGridView.setNumColumns(GridView.AUTO_FIT);
-                mGridView.setHorizontalSpacing(0);
-                mGridView.setVerticalSpacing(0);
-                mGridView.setColumnWidth(0);
-            }
+    public void testAccessColumnWidth() {
+        mActivity.runOnUiThread(() -> {
+            mGridView.setAdapter(new MockGridViewAdapter(10));
+            mGridView.setNumColumns(GridView.AUTO_FIT);
+            mGridView.setHorizontalSpacing(0);
+            mGridView.setVerticalSpacing(0);
+            mGridView.setColumnWidth(0);
         });
         mInstrumentation.waitForIdleSync();
 
         // Verify whether column number equals 2.
+        assertEquals(0, mGridView.getRequestedColumnWidth());
+        assertEquals(mGridView.getWidth() / 2, mGridView.getColumnWidth());
         View child0 = mGridView.getChildAt(0);
         View child1 = mGridView.getChildAt(1);
         View child2 = mGridView.getChildAt(2);
         assertEquals(child0.getBottom(), child1.getBottom());
         assertEquals(child0.getLeft(), child2.getLeft());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setNumColumns(GridView.AUTO_FIT);
-                mGridView.setColumnWidth(Integer.MAX_VALUE);
-            }
+        mActivity.runOnUiThread(() -> {
+            mGridView.setNumColumns(GridView.AUTO_FIT);
+            mGridView.setColumnWidth(Integer.MAX_VALUE);
         });
         mInstrumentation.waitForIdleSync();
 
+        assertEquals(Integer.MAX_VALUE, mGridView.getRequestedColumnWidth());
+        assertEquals(mGridView.getWidth(), mGridView.getColumnWidth());
         child0 = mGridView.getChildAt(0);
         child1 = mGridView.getChildAt(1);
         assertEquals(child0.getBottom(), child1.getTop());
@@ -570,20 +552,19 @@
 
     @MediumTest
     public void testFullyDetachUnusedViewOnScroll() {
-        mGridView = findGridViewById(R.id.gridview);
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
             mGridView.setAdapter(new DummyAdapter(1000, theView));
         });
         assertEquals("test sanity", 1, theView.mOnAttachCount);
         assertEquals("test sanity", 0, theView.mOnDetachCount);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
             mGridView.scrollListBy(mGridView.getHeight() * 2);
         });
         assertNull("test sanity, unused view should be removed", theView.getParent());
         assertEquals("unused view should be detached", 1, theView.mOnDetachCount);
         assertFalse(theView.isTemporarilyDetached());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
             mGridView.scrollListBy(-mGridView.getHeight() * 2);
             // listview limits scroll to 1 page which is why we call it twice here.
             mGridView.scrollListBy(-mGridView.getHeight() * 2);
@@ -596,20 +577,19 @@
 
     @MediumTest
     public void testFullyDetachUnusedViewOnReLayout() {
-        mGridView = findGridViewById(R.id.gridview);
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
             mGridView.setAdapter(new DummyAdapter(1000, theView));
         });
         assertEquals("test sanity", 1, theView.mOnAttachCount);
         assertEquals("test sanity", 0, theView.mOnDetachCount);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
             mGridView.setSelection(800);
         });
         assertNull("test sanity, unused view should be removed", theView.getParent());
         assertEquals("unused view should be detached", 1, theView.mOnDetachCount);
         assertFalse(theView.isTemporarilyDetached());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
             mGridView.setSelection(0);
         });
         assertNotNull("test sanity, view should be re-added", theView.getParent());
@@ -620,9 +600,8 @@
 
     @MediumTest
     public void testFullyDetachUnusedViewOnScrollForFocus() {
-        mGridView = findGridViewById(R.id.gridview);
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
             mGridView.setAdapter(new DummyAdapter(1000, theView));
         });
         assertEquals("test sanity", 1, theView.mOnAttachCount);
@@ -630,33 +609,72 @@
         while(theView.getParent() != null) {
             assertEquals("the view should NOT be detached", 0, theView.mOnDetachCount);
             sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-            ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, null);
+            WidgetTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, null);
         }
         assertEquals("the view should be detached", 1, theView.mOnDetachCount);
         assertFalse(theView.isTemporarilyDetached());
         while(theView.getParent() == null) {
             sendKeys(KeyEvent.KEYCODE_DPAD_UP);
-            ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, null);
+            WidgetTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, null);
         }
         assertEquals("the view should be re-attached", 2, theView.mOnAttachCount);
-        assertEquals("the view should not recieve another detach", 1, theView.mOnDetachCount);
+        assertEquals("the view should not receive another detach", 1, theView.mOnDetachCount);
         assertFalse(theView.isTemporarilyDetached());
     }
 
-    private static class MockGridView extends GridView {
-        private boolean mCalledOnMeasure = false;
-        private boolean mCalledOnFocusChanged = false;
+    @LargeTest
+    public void testSmoothScrollByOffset() {
+        final int itemCount = 300;
+        mActivity.runOnUiThread(() -> {
+            mGridView.setAdapter(new MockGridViewAdapter(itemCount));
+            mGridView.setNumColumns(GridView.AUTO_FIT);
+            mGridView.setHorizontalSpacing(0);
+            mGridView.setVerticalSpacing(0);
+            mGridView.setColumnWidth(Integer.MAX_VALUE);
+        });
+        mInstrumentation.waitForIdleSync();
 
-        public boolean hasCalledOnMeasure() {
-            return mCalledOnMeasure;
+        assertEquals(0, mGridView.getFirstVisiblePosition());
+
+        // Register a scroll listener on our GridView. The listener will notify our latch
+        // when the "target" item comes into view. If that never happens, the latch will
+        // time out and fail the test.
+        final CountDownLatch latch = new CountDownLatch(1);
+        final int positionToScrollTo = itemCount - 10;
+        mGridView.setOnScrollListener(new AbsListView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(AbsListView view, int scrollState) {
+            }
+
+            @Override
+            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+                    int totalItemCount) {
+                if ((positionToScrollTo >= firstVisibleItem) &&
+                        (positionToScrollTo <= (firstVisibleItem + visibleItemCount))) {
+                    latch.countDown();
+                }
+            }
+        });
+        int offset = positionToScrollTo - mGridView.getLastVisiblePosition();
+        mActivity.runOnUiThread(() -> mGridView.smoothScrollByOffset(offset));
+
+        boolean result = false;
+        try {
+            result = latch.await(20, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
         }
+        assertTrue("Timed out while waiting for the target view to be scrolled into view", result);
+    }
+
+    private static class MockGridView extends GridView {
+        private boolean mCalledOnFocusChanged = false;
 
         public boolean hasCalledOnFocusChanged() {
             return mCalledOnFocusChanged;
         }
 
         public void reset() {
-            mCalledOnMeasure = false;
             mCalledOnFocusChanged = false;
         }
 
@@ -684,48 +702,11 @@
         }
 
         @Override
-        protected int computeVerticalScrollExtent() {
-            return super.computeVerticalScrollExtent();
-        }
-
-        @Override
-        protected int computeVerticalScrollOffset() {
-            return super.computeVerticalScrollOffset();
-        }
-
-        @Override
-        protected int computeVerticalScrollRange() {
-            return super.computeVerticalScrollRange();
-        }
-
-        @Override
         protected void onFocusChanged(boolean gainFocus, int direction,
                 Rect previouslyFocusedRect) {
             mCalledOnFocusChanged = true;
             super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
         }
-
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            mCalledOnMeasure = true;
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-    }
-
-    class MockOnItemClickListener implements OnItemClickListener {
-        private boolean mOnItemClickCalled = false;
-
-        public boolean hasOnItemClickCalled() {
-            return mOnItemClickCalled;
-        }
-
-        public void reset() {
-            mOnItemClickCalled = false;
-        }
-
-        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-            mOnItemClickCalled = true;
-        }
     }
 
     private class MockGridViewAdapter implements ListAdapter, Filterable {
@@ -735,10 +716,6 @@
             mCount = count;
         }
 
-        MockGridViewAdapter() {
-            this(1);
-        }
-
         public boolean areAllItemsEnabled() {
             return true;
         }
diff --git a/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java b/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java
index 2b92a4d..b57dc77 100644
--- a/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java
@@ -16,6 +16,8 @@
 
 package android.widget.cts;
 
+import static org.mockito.Mockito.*;
+
 import android.content.Context;
 import android.database.DataSetObserver;
 import android.test.InstrumentationTestCase;
@@ -334,21 +336,21 @@
         HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
         HeaderViewListAdapter headerViewListAdapter =
             new HeaderViewListAdapter(null, null, fullAdapter);
-        DataSetObserver observer = new HeaderViewDataSetObserver();
-        headerViewListAdapter.registerDataSetObserver(observer);
-        assertSame(observer, fullAdapter.getDataSetObserver());
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        headerViewListAdapter.registerDataSetObserver(mockDataSetObserver);
+        assertSame(mockDataSetObserver, fullAdapter.getDataSetObserver());
     }
 
     public void testUnregisterDataSetObserver() {
         HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
         HeaderViewListAdapter headerViewListAdapter =
             new HeaderViewListAdapter(null, null, fullAdapter);
-        DataSetObserver observer = new HeaderViewDataSetObserver();
-        headerViewListAdapter.registerDataSetObserver(observer);
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        headerViewListAdapter.registerDataSetObserver(mockDataSetObserver);
 
         headerViewListAdapter.unregisterDataSetObserver(null);
-        assertSame(observer, fullAdapter.getDataSetObserver());
-        headerViewListAdapter.unregisterDataSetObserver(observer);
+        assertSame(mockDataSetObserver, fullAdapter.getDataSetObserver());
+        headerViewListAdapter.unregisterDataSetObserver(mockDataSetObserver);
         assertNull(fullAdapter.getDataSetObserver());
     }
 
@@ -504,16 +506,4 @@
         protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
         }
     }
-
-    private class HeaderViewDataSetObserver extends DataSetObserver {
-        @Override
-        public void onChanged() {
-            // Do nothing
-        }
-
-        @Override
-        public void onInvalidated() {
-            // Do nothing
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java
index a10e63a..96d8279 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 public class HorizontalScrollViewCtsActivity extends Activity {
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
index afdc869..c8a7095 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
@@ -16,11 +16,8 @@
 
 package android.widget.cts;
 
-import android.widget.FrameLayout;
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
 import android.content.Context;
@@ -32,13 +29,13 @@
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
 import android.widget.HorizontalScrollView;
 import android.widget.TextView;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
+
+import org.xmlpull.v1.XmlPullParser;
 
 /**
  * Test {@link HorizontalScrollView}.
@@ -800,55 +797,34 @@
         }
 
         if (fromY != toY) {
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return isInRange(mScrollView.getScrollY(), fromY, toY);
-                }
-            }.run();
+            PollingCheck.waitFor(() -> isInRange(mScrollView.getScrollY(), fromY, toY));
         }
 
         if (fromX != toX) {
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return isInRange(mScrollView.getScrollX(), fromX, toX);
-                }
-            }.run();
+            PollingCheck.waitFor(() -> isInRange(mScrollView.getScrollX(), fromX, toX));
         }
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return toX == mScrollView.getScrollX() && toY == mScrollView.getScrollY();
-            }
-        }.run();
+        PollingCheck.waitFor(
+                () -> toX == mScrollView.getScrollX() && toY == mScrollView.getScrollY());
     }
 
     private void pollingCheckFling(final int startPosition, final boolean movingRight) {
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                if (movingRight) {
-                    return mScrollView.getScrollX() > startPosition;
-                }
-                return mScrollView.getScrollX() < startPosition;
+        PollingCheck.waitFor(() -> {
+            if (movingRight) {
+                return mScrollView.getScrollX() > startPosition;
             }
-        }.run();
+            return mScrollView.getScrollX() < startPosition;
+        });
 
-        new PollingCheck() {
-            private int mPreviousScrollX = mScrollView.getScrollX();
-
-            @Override
-            protected boolean check() {
-                if (mScrollView.getScrollX() == mPreviousScrollX) {
-                    return true;
-                } else {
-                    mPreviousScrollX = mScrollView.getScrollX();
-                    return false;
-                }
+        final int[] previousScrollX = new int[] { mScrollView.getScrollX() };
+        PollingCheck.waitFor(() -> {
+            if (mScrollView.getScrollX() == previousScrollX[0]) {
+                return true;
+            } else {
+                previousScrollX[0] = mScrollView.getScrollX();
+                return false;
             }
-        }.run();
+        });
     }
 
     public static class MyView extends View {
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/ImageButtonCtsActivity.java
similarity index 67%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/ImageButtonCtsActivity.java
index 481f5be..5f91950 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageButtonCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.ImageButton;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link ImageButton} test.
+ */
+public class ImageButtonCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.imagebutton_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java b/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
index 05c0e3f..485024b 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
@@ -16,27 +16,42 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
-import android.util.Xml;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.ImageButton;
+import android.widget.cts.util.TestUtils;
 
-public class ImageButtonTest extends AndroidTestCase {
+@SmallTest
+public class ImageButtonTest extends ActivityInstrumentationTestCase2<ImageButtonCtsActivity> {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private ImageButton mImageButton;
+
+    public ImageButtonTest() {
+        super("android.widget.cts", ImageButtonCtsActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+        mImageButton = (ImageButton) mActivity.findViewById(R.id.image_button);
+    }
+
     public void testConstructor() {
-        XmlPullParser parser = getContext().getResources().getXml(R.layout.imagebutton_test);
-        AttributeSet attrs = Xml.asAttributeSet(parser);
-        assertNotNull(attrs);
-
-        new ImageButton(getContext());
-
-        new ImageButton(getContext(), attrs);
-
-        new ImageButton(getContext(), attrs, 0);
+        new ImageButton(mActivity);
+        new ImageButton(mActivity, null);
+        new ImageButton(mActivity, null, android.R.attr.imageButtonStyle);
+        new ImageButton(mActivity, null, 0, android.R.style.Widget_DeviceDefault_ImageButton);
+        new ImageButton(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Light_ImageButton);
+        new ImageButton(mActivity, null, 0, android.R.style.Widget_Material_ImageButton);
+        new ImageButton(mActivity, null, 0, android.R.style.Widget_Material_Light_ImageButton);
 
         try {
             new ImageButton(null);
@@ -57,7 +72,23 @@
         }
     }
 
-    public void testOnSetAlpha() {
-        // Do not test, it's controlled by View. Implementation details.
+    public void testImageSource() {
+        Drawable imageButtonDrawable = mImageButton.getDrawable();
+        TestUtils.assertAllPixelsOfColor("Default source is red", imageButtonDrawable,
+                imageButtonDrawable.getIntrinsicWidth(), imageButtonDrawable.getIntrinsicHeight(),
+                true, Color.RED, 1, false);
+
+        mInstrumentation.runOnMainSync(() -> mImageButton.setImageResource(R.drawable.icon_green));
+        imageButtonDrawable = mImageButton.getDrawable();
+        TestUtils.assertAllPixelsOfColor("New source is green", imageButtonDrawable,
+                imageButtonDrawable.getIntrinsicWidth(), imageButtonDrawable.getIntrinsicHeight(),
+                true, Color.GREEN, 1, false);
+
+        mInstrumentation.runOnMainSync(
+                () -> mImageButton.setImageDrawable(mActivity.getDrawable(R.drawable.icon_yellow)));
+        imageButtonDrawable = mImageButton.getDrawable();
+        TestUtils.assertAllPixelsOfColor("New source is yellow", imageButtonDrawable,
+                imageButtonDrawable.getIntrinsicWidth(), imageButtonDrawable.getIntrinsicHeight(),
+                true, Color.YELLOW, 1, false);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
index a7bca5c..9c559fa 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
@@ -16,16 +16,10 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.content.Context;
 import android.content.res.Resources;
 import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -34,6 +28,9 @@
 import android.util.Xml;
 import android.widget.ImageSwitcher;
 import android.widget.ImageView;
+import android.widget.cts.R;
+
+import org.xmlpull.v1.XmlPullParser;
 
 import java.io.File;
 import java.io.FileOutputStream;
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ImageViewCtsActivity.java
index e68c986..c3529ee 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 /**
  * A minimal application for {@link ImageView} test.
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
index 844b922..664bdbe 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -16,48 +16,44 @@
 
 package android.widget.cts;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-
-import android.graphics.drawable.ColorDrawable;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.widget.cts.util.TestUtils;
-import android.widget.cts.util.ViewTestUtils;
-import org.junit.Assert;
-import org.xmlpull.v1.XmlPullParser;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.Matrix;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.graphics.drawable.PaintDrawable;
 import android.net.Uri;
 import android.test.ActivityInstrumentationTestCase;
 import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
-import android.util.StateSet;
 import android.util.Xml;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
-
 import android.widget.cts.R;
+import android.widget.cts.util.TestUtils;
 
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.*;
+import org.junit.Assert;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 
 
 /**
diff --git a/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java b/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java
index 2369c5a..73517cb 100644
--- a/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java
@@ -16,17 +16,21 @@
 
 package android.widget.cts;
 
+import static android.view.View.LAYOUT_DIRECTION_INHERIT;
+import static android.view.View.LAYOUT_DIRECTION_LOCALE;
+import static android.view.View.LAYOUT_DIRECTION_LTR;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
+
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.view.ViewGroup;
-import android.widget.*;
+import android.widget.FrameLayout;
+import android.widget.GridLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TableLayout;
 import android.widget.cts.R;
 
-import static android.view.View.LAYOUT_DIRECTION_LTR;
-import static android.view.View.LAYOUT_DIRECTION_RTL;
-import static android.view.View.LAYOUT_DIRECTION_INHERIT;
-import static android.view.View.LAYOUT_DIRECTION_LOCALE;
-
 public class LayoutDirectionTest extends ActivityInstrumentationTestCase2<LayoutDirectionCtsActivity> {
 
     public LayoutDirectionTest() {
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayoutCtsActivity.java b/tests/tests/widget/src/android/widget/cts/LinearLayoutCtsActivity.java
index 4a04b52..c906342 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 /**
  * A minimal application for {@link LinearLayout} test.
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
index 4d0903a..068c363 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
@@ -16,15 +16,21 @@
 
 package android.widget.cts;
 
-import org.xmlpull.v1.XmlPullParser;
-
+import android.annotation.ColorInt;
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
+import android.content.res.Resources;
+import android.cts.util.WidgetTestUtils;
 import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.test.ActivityInstrumentationTestCase;
 import android.test.ViewAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
+import android.view.Gravity;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
@@ -34,7 +40,9 @@
 import android.widget.LinearLayout.LayoutParams;
 import android.widget.ListView;
 import android.widget.TextView;
-import android.widget.cts.R;
+import android.widget.cts.util.TestUtils;
+
+import org.xmlpull.v1.XmlPullParser;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -42,6 +50,7 @@
 /**
  * Test {@link LinearLayout}.
  */
+@SmallTest
 public class LinearLayoutTest extends ActivityInstrumentationTestCase<LinearLayoutCtsActivity> {
     private Context mContext;
     private Activity mActivity;
@@ -152,9 +161,9 @@
      */
     public void testAccessWeightSum() {
         LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum);
-        TextView weight02 = (TextView) mActivity.findViewById(R.id.weight_0_2);
-        TextView weight05 = (TextView) mActivity.findViewById(R.id.weight_0_5);
-        TextView weight03 = (TextView) mActivity.findViewById(R.id.weight_0_3);
+        TextView weight02 = (TextView) parent.findViewById(R.id.weight_0_2);
+        TextView weight05 = (TextView) parent.findViewById(R.id.weight_0_5);
+        TextView weight03 = (TextView) parent.findViewById(R.id.weight_0_3);
 
         assertNotNull(parent);
         assertNotNull(weight02);
@@ -399,6 +408,182 @@
         assertEquals(parent.getWidth(), rightView.getRight());
     }
 
+    public void testVerticalCenterGravityOnHorizontalLayout() {
+        final Instrumentation instrumentation = getInstrumentation();
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum);
+        TextView leftView = (TextView) parent.findViewById(R.id.weight_0_2);
+        TextView centerView = (TextView) parent.findViewById(R.id.weight_0_5);
+        TextView rightView = (TextView) parent.findViewById(R.id.weight_0_3);
+
+        instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        instrumentation.waitForIdleSync();
+
+        int originalLeftViewRight = leftView.getRight();
+        int originalCenterViewLeft = centerView.getLeft();
+        int originalCenterViewRight = centerView.getRight();
+        int originalRightViewLeft = rightView.getLeft();
+
+        instrumentation.runOnMainSync(() -> parent.setVerticalGravity(Gravity.CENTER_VERTICAL));
+        instrumentation.waitForIdleSync();
+
+        assertEquals(Gravity.CENTER_VERTICAL, parent.getGravity() & Gravity.VERTICAL_GRAVITY_MASK);
+
+        ViewAsserts.assertVerticalCenterAligned(parent, leftView);
+        ViewAsserts.assertVerticalCenterAligned(parent, centerView);
+        ViewAsserts.assertVerticalCenterAligned(parent, rightView);
+
+        final int parentHeight = parent.getHeight();
+
+        int verticalOffset = (parentHeight - leftView.getHeight()) / 2;
+        assertEquals(verticalOffset, leftView.getTop());
+        assertEquals(verticalOffset + leftView.getHeight(), leftView.getBottom());
+        assertEquals(0, leftView.getLeft());
+        assertEquals(originalLeftViewRight, leftView.getRight());
+
+        verticalOffset = (parentHeight - centerView.getHeight()) / 2;
+        assertEquals(verticalOffset, centerView.getTop());
+        assertEquals(verticalOffset + centerView.getHeight(), centerView.getBottom());
+        assertEquals(originalCenterViewLeft, centerView.getLeft());
+        assertEquals(originalCenterViewRight, centerView.getRight());
+
+        verticalOffset = (parentHeight - rightView.getHeight()) / 2;
+        assertEquals(verticalOffset, rightView.getTop());
+        assertEquals(verticalOffset + rightView.getHeight(), rightView.getBottom());
+        assertEquals(originalRightViewLeft, rightView.getLeft());
+        assertEquals(parent.getWidth(), rightView.getRight());
+    }
+
+    public void testBottomGravityOnHorizontalLayout() {
+        final Instrumentation instrumentation = getInstrumentation();
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum);
+        TextView leftView = (TextView) parent.findViewById(R.id.weight_0_2);
+        TextView centerView = (TextView) parent.findViewById(R.id.weight_0_5);
+        TextView rightView = (TextView) parent.findViewById(R.id.weight_0_3);
+
+        instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        instrumentation.waitForIdleSync();
+
+        int originalLeftViewRight = leftView.getRight();
+        int originalCenterViewLeft = centerView.getLeft();
+        int originalCenterViewRight = centerView.getRight();
+        int originalRightViewLeft = rightView.getLeft();
+
+        instrumentation.runOnMainSync(() -> parent.setVerticalGravity(Gravity.BOTTOM));
+        instrumentation.waitForIdleSync();
+
+        assertEquals(Gravity.BOTTOM, parent.getGravity() & Gravity.VERTICAL_GRAVITY_MASK);
+
+        ViewAsserts.assertBottomAligned(parent, leftView);
+        ViewAsserts.assertBottomAligned(parent, centerView);
+        ViewAsserts.assertBottomAligned(parent, rightView);
+
+        final int parentHeight = parent.getHeight();
+
+        assertEquals(parentHeight - leftView.getHeight(), leftView.getTop());
+        assertEquals(parentHeight, leftView.getBottom());
+        assertEquals(0, leftView.getLeft());
+        assertEquals(originalLeftViewRight, leftView.getRight());
+
+        assertEquals(parentHeight - centerView.getHeight(), centerView.getTop());
+        assertEquals(parentHeight, centerView.getBottom());
+        assertEquals(originalCenterViewLeft, centerView.getLeft());
+        assertEquals(originalCenterViewRight, centerView.getRight());
+
+        assertEquals(parentHeight - rightView.getHeight(), rightView.getTop());
+        assertEquals(parentHeight, rightView.getBottom());
+        assertEquals(originalRightViewLeft, rightView.getLeft());
+        assertEquals(parent.getWidth(), rightView.getRight());
+    }
+
+    public void testHorizontalCenterGravityOnVerticalLayout() {
+        final Instrumentation instrumentation = getInstrumentation();
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum_vertical);
+        TextView topView = (TextView) parent.findViewById(R.id.weight_0_1);
+        TextView centerView = (TextView) parent.findViewById(R.id.weight_0_4);
+        TextView bottomView = (TextView) parent.findViewById(R.id.weight_0_5);
+
+        instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        instrumentation.waitForIdleSync();
+
+        final int parentWidth = parent.getHeight();
+
+        int originalTopViewBottom = topView.getBottom();
+        int originalCenterViewTop = centerView.getTop();
+        int originalCenterViewBottom = centerView.getBottom();
+        int originalBottomViewTop = bottomView.getTop();
+
+        instrumentation.runOnMainSync(() -> parent.setHorizontalGravity(Gravity.CENTER_HORIZONTAL));
+        instrumentation.waitForIdleSync();
+
+        assertEquals(Gravity.CENTER_HORIZONTAL,
+                parent.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK);
+
+        ViewAsserts.assertHorizontalCenterAligned(parent, topView);
+        ViewAsserts.assertHorizontalCenterAligned(parent, centerView);
+        ViewAsserts.assertHorizontalCenterAligned(parent, bottomView);
+
+        int horizontalOffset = (parentWidth - topView.getWidth()) / 2;
+        assertEquals(0, topView.getTop());
+        assertEquals(originalTopViewBottom, topView.getBottom());
+        assertEquals(horizontalOffset, topView.getLeft());
+        assertEquals(horizontalOffset + topView.getWidth(), topView.getRight());
+
+        horizontalOffset = (parentWidth - centerView.getWidth()) / 2;
+        assertEquals(originalCenterViewTop, centerView.getTop());
+        assertEquals(originalCenterViewBottom, centerView.getBottom());
+        assertEquals(horizontalOffset, centerView.getLeft());
+        assertEquals(horizontalOffset + centerView.getWidth(), centerView.getRight());
+
+        horizontalOffset = (parentWidth - bottomView.getWidth()) / 2;
+        assertEquals(originalBottomViewTop, bottomView.getTop());
+        assertEquals(parent.getHeight(), bottomView.getBottom());
+        assertEquals(horizontalOffset, bottomView.getLeft());
+        assertEquals(horizontalOffset + bottomView.getWidth(), bottomView.getRight());
+    }
+
+    public void testRightGravityOnVerticalLayout() {
+        final Instrumentation instrumentation = getInstrumentation();
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum_vertical);
+        TextView topView = (TextView) parent.findViewById(R.id.weight_0_1);
+        TextView centerView = (TextView) parent.findViewById(R.id.weight_0_4);
+        TextView bottomView = (TextView) parent.findViewById(R.id.weight_0_5);
+
+        instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        instrumentation.waitForIdleSync();
+
+        final int parentWidth = parent.getHeight();
+
+        int originalTopViewBottom = topView.getBottom();
+        int originalCenterViewTop = centerView.getTop();
+        int originalCenterViewBottom = centerView.getBottom();
+        int originalBottomViewTop = bottomView.getTop();
+
+        instrumentation.runOnMainSync(() -> parent.setHorizontalGravity(Gravity.RIGHT));
+        instrumentation.waitForIdleSync();
+
+        assertEquals(Gravity.RIGHT,
+                parent.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK);
+
+        ViewAsserts.assertRightAligned(parent, topView);
+        ViewAsserts.assertRightAligned(parent, centerView);
+        ViewAsserts.assertRightAligned(parent, bottomView);
+
+        assertEquals(0, topView.getTop());
+        assertEquals(originalTopViewBottom, topView.getBottom());
+        assertEquals(parentWidth - topView.getWidth(), topView.getLeft());
+        assertEquals(parentWidth, topView.getRight());
+
+        assertEquals(originalCenterViewTop, centerView.getTop());
+        assertEquals(originalCenterViewBottom, centerView.getBottom());
+        assertEquals(parentWidth - centerView.getWidth(), centerView.getLeft());
+        assertEquals(parentWidth, centerView.getRight());
+
+        assertEquals(originalBottomViewTop, bottomView.getTop());
+        assertEquals(parent.getHeight(), bottomView.getBottom());
+        assertEquals(parentWidth - bottomView.getWidth(), bottomView.getLeft());
+        assertEquals(parentWidth, bottomView.getRight());
+    }
+
     private void checkBounds(final ViewGroup viewGroup, final View view,
             final CountDownLatch countDownLatch, final int left, final int top,
             final int width, final int height) {
@@ -471,6 +656,523 @@
         countDownLatch3.await(500, TimeUnit.MILLISECONDS);
     }
 
+    private void verifyVisualsOfVerticalLayoutWithDivider(LinearLayout parent,
+            int expectedDividerPositionMask,
+            int expectedDividerSize, @ColorInt int expectedDividerColor,
+            int expectedDividerPadding) {
+        final int parentWidth = parent.getWidth();
+        final int parentHeight = parent.getHeight();
+
+        final boolean expectingTopDivider =
+                (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_BEGINNING) != 0;
+        final boolean expectingMiddleDivider =
+                (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_MIDDLE) != 0;
+        final boolean expectingBottomDivider =
+                (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_END) != 0;
+        final int expectedDividerCount = (expectingTopDivider ? 1 : 0)
+                + (expectingMiddleDivider ? 1 : 0) + (expectingBottomDivider ? 1 : 0);
+
+        final int expectedChildHeight =
+                (parentHeight - expectedDividerCount * expectedDividerSize) / 2;
+
+        final int expectedTopChildTop = expectingTopDivider ? expectedDividerSize : 0;
+        TestUtils.assertRegionPixelsOfColor("Region of first child is blue", parent,
+                new Rect(0, expectedTopChildTop, parentWidth,
+                        expectedTopChildTop + expectedChildHeight),
+                Color.BLUE, 1, true);
+
+        final int expectedBottomChildBottom =
+                expectingBottomDivider ? parentHeight - expectedDividerSize : parentHeight;
+        TestUtils.assertRegionPixelsOfColor("Region of second child is green", parent,
+                new Rect(0, expectedBottomChildBottom - expectedChildHeight, parentWidth,
+                        expectedBottomChildBottom),
+                Color.GREEN, 1, true);
+
+        if (expectedDividerSize == 0) {
+            return;
+        }
+
+        // Do we expect top divider?
+        if (expectingTopDivider) {
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of top divider is " + TestUtils.formatColorToHex(expectedDividerColor),
+                    parent,
+                    new Rect(expectedDividerPadding, 0, parentWidth - expectedDividerPadding,
+                            expectedDividerSize),
+                    expectedDividerColor, 1, true);
+            TestUtils.assertRegionPixelsOfColor("Region of left padding of top divider is yellow",
+                    parent,
+                    new Rect(0, 0, expectedDividerPadding, expectedDividerSize),
+                    Color.YELLOW, 1, true);
+            TestUtils.assertRegionPixelsOfColor("Region of right padding of top divider is yellow",
+                    parent,
+                    new Rect(parentWidth - expectedDividerPadding, 0, parentWidth,
+                            expectedDividerSize),
+                    Color.YELLOW, 1, true);
+        }
+
+        // Do we expect middle divider?
+        if (expectingMiddleDivider) {
+            final int expectedMiddleDividerTop = expectedTopChildTop + expectedChildHeight;
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of middle divider is " +
+                            TestUtils.formatColorToHex(expectedDividerColor),
+                    parent,
+                    new Rect(expectedDividerPadding, expectedMiddleDividerTop,
+                            parentWidth - expectedDividerPadding,
+                            expectedMiddleDividerTop + expectedDividerSize),
+                    expectedDividerColor, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of left padding of middle divider is yellow",
+                    parent,
+                    new Rect(0, expectedMiddleDividerTop, expectedDividerPadding,
+                            expectedMiddleDividerTop + expectedDividerSize),
+                    Color.YELLOW, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of right padding of middle divider is yellow",
+                    parent,
+                    new Rect(parentWidth - expectedDividerPadding, expectedMiddleDividerTop,
+                            parentWidth, expectedMiddleDividerTop + expectedDividerSize),
+                    Color.YELLOW, 1, true);
+        }
+
+        // Do we expect bottom divider?
+        if (expectingBottomDivider) {
+            final int expectedBottomDividerTop = expectedBottomChildBottom;
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of bottom divider is " +
+                            TestUtils.formatColorToHex(expectedDividerColor),
+                    parent,
+                    new Rect(expectedDividerPadding, expectedBottomDividerTop,
+                            parentWidth - expectedDividerPadding,
+                            expectedBottomDividerTop + expectedDividerSize),
+                    expectedDividerColor, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of left padding of bottom divider is yellow",
+                    parent,
+                    new Rect(0, expectedBottomDividerTop, expectedDividerPadding,
+                            expectedBottomDividerTop + expectedDividerSize),
+                    Color.YELLOW, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of right padding of bottom divider is yellow",
+                    parent,
+                    new Rect(parentWidth - expectedDividerPadding, expectedBottomDividerTop,
+                            parentWidth, expectedBottomDividerTop + expectedDividerSize),
+                    Color.YELLOW, 1, true);
+        }
+    }
+
+    /**
+     * layout of vertical LinearLayout.
+     * -----------------------------------
+     * | ------------------------------- |
+     * | |            child1           | |
+     * | ------------------------------- |
+     * | - - - - - - divider - - - - - - |
+     * | ------------------------------- |
+     * | |            child2           | |
+     * | ------------------------------- |
+     * -----------------------------------
+     *
+     * Parent is filled with yellow color. Child 1 is filled with green and child 2 is filled
+     * with blue. Divider is red at the beginning. Throughout this method we reconfigure the
+     * visibility, drawable and paddings of the divider and verify the overall visuals of the
+     * container.
+     */
+    public void testDividersInVerticalLayout() {
+        final LinearLayout parent =
+                (LinearLayout) mActivity.findViewById(R.id.vertical_with_divider);
+
+        final Instrumentation instrumentation = getInstrumentation();
+
+        final Resources res = mActivity.getResources();
+        final int dividerSize = res.getDimensionPixelSize(R.dimen.linear_layout_divider_size);
+        final int dividerPadding = res.getDimensionPixelSize(R.dimen.linear_layout_divider_padding);
+
+        assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE, parent.getShowDividers());
+        assertEquals(dividerPadding, parent.getDividerPadding());
+        final Drawable dividerDrawable = parent.getDividerDrawable();
+        TestUtils.assertAllPixelsOfColor("Divider is red", dividerDrawable,
+                dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
+                false, Color.RED, 1, true);
+
+        // Test the initial visuals of the entire parent
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Change the divider to magenta
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerDrawable(
+                        mActivity.getDrawable(R.drawable.linear_layout_divider_magenta)));
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.MAGENTA, dividerPadding);
+
+        // Change the divider to null (no divider effectively)
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerDrawable(null));
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                0, Color.TRANSPARENT, 0);
+
+        // Change the divider back to red
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerDrawable(
+                        mActivity.getDrawable(R.drawable.linear_layout_divider_red)));
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Change the padding to half the original size
+        final int halfPadding = dividerPadding / 2;
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerPadding(halfPadding));
+        assertEquals(halfPadding, parent.getDividerPadding());
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, halfPadding);
+
+        // Change the padding to twice the original size
+        final int doublePadding = dividerPadding * 2;
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerPadding(doublePadding));
+        assertEquals(doublePadding, parent.getDividerPadding());
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, doublePadding);
+
+        // And back to the original padding
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerPadding(dividerPadding));
+        assertEquals(dividerPadding, parent.getDividerPadding());
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Set show dividers to NONE (no divider effectively)
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE));
+        assertEquals(LinearLayout.SHOW_DIVIDER_NONE, parent.getShowDividers());
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_NONE,
+                0, Color.TRANSPARENT, 0);
+
+        // Show only top divider
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING));
+        assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING, parent.getShowDividers());
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_BEGINNING,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show only bottom divider
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_END));
+        assertEquals(LinearLayout.SHOW_DIVIDER_END, parent.getShowDividers());
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_END,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show top and bottom dividers
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(
+                        LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END));
+        assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
+                parent.getShowDividers());
+        verifyVisualsOfVerticalLayoutWithDivider(parent,
+                LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show top and middle dividers
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(
+                        LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE));
+        assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
+                parent.getShowDividers());
+        verifyVisualsOfVerticalLayoutWithDivider(parent,
+                LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show middle and bottom dividers
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(
+                        LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END));
+        assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
+                parent.getShowDividers());
+        verifyVisualsOfVerticalLayoutWithDivider(parent,
+                LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show top, middle and bottom dividers
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(
+                        LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+                                | LinearLayout.SHOW_DIVIDER_END));
+        assertEquals(
+                LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+                        | LinearLayout.SHOW_DIVIDER_END,
+                parent.getShowDividers());
+        verifyVisualsOfVerticalLayoutWithDivider(parent,
+                LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+                        | LinearLayout.SHOW_DIVIDER_END,
+                dividerSize, Color.RED, dividerPadding);
+    }
+
+    private void verifyVisualsOfHorizontalLayoutWithDivider(LinearLayout parent,
+            int expectedDividerPositionMask,
+            int expectedDividerSize, @ColorInt int expectedDividerColor,
+            int expectedDividerPadding) {
+        final int parentWidth = parent.getWidth();
+        final int parentHeight = parent.getHeight();
+
+        final boolean expectingLeftDivider =
+                (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_BEGINNING) != 0;
+        final boolean expectingMiddleDivider =
+                (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_MIDDLE) != 0;
+        final boolean expectingRightDivider =
+                (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_END) != 0;
+        final int expectedDividerCount = (expectingLeftDivider ? 1 : 0)
+                + (expectingMiddleDivider ? 1 : 0) + (expectingRightDivider ? 1 : 0);
+
+        final int expectedChildWidth =
+                (parentWidth - expectedDividerCount * expectedDividerSize) / 2;
+
+        final int expectedLeftChildLeft = expectingLeftDivider ? expectedDividerSize : 0;
+        TestUtils.assertRegionPixelsOfColor("Region of first child is blue", parent,
+                new Rect(expectedLeftChildLeft, 0,
+                        expectedLeftChildLeft + expectedChildWidth, parentHeight),
+                Color.BLUE, 1, true);
+
+        final int expectedRightChildRight =
+                expectingRightDivider ? parentWidth - expectedDividerSize : parentWidth;
+        TestUtils.assertRegionPixelsOfColor("Region of second child is green", parent,
+                new Rect(expectedRightChildRight - expectedChildWidth, 0, expectedRightChildRight,
+                        parentHeight),
+                Color.GREEN, 1, true);
+
+        if (expectedDividerSize == 0) {
+            return;
+        }
+
+        // Do we expect left divider?
+        if (expectingLeftDivider) {
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of left divider is " + TestUtils.formatColorToHex(expectedDividerColor),
+                    parent,
+                    new Rect(0, expectedDividerPadding, expectedDividerSize,
+                            parentHeight - expectedDividerPadding),
+                    expectedDividerColor, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of top padding of left divider is yellow",
+                    parent,
+                    new Rect(0, 0, expectedDividerSize, expectedDividerPadding),
+                    Color.YELLOW, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of bottom padding of left divider is yellow",
+                    parent,
+                    new Rect(0, parentHeight - expectedDividerPadding, expectedDividerSize,
+                            parentHeight),
+                    Color.YELLOW, 1, true);
+        }
+
+        // Do we expect middle divider?
+        if (expectingMiddleDivider) {
+            final int expectedMiddleDividerLeft = expectedLeftChildLeft + expectedChildWidth;
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of middle divider is " +
+                            TestUtils.formatColorToHex(expectedDividerColor),
+                    parent,
+                    new Rect(expectedMiddleDividerLeft, expectedDividerPadding,
+                            expectedMiddleDividerLeft + expectedDividerSize,
+                            parentHeight - expectedDividerPadding),
+                    expectedDividerColor, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of top padding of middle divider is yellow",
+                    parent,
+                    new Rect(expectedMiddleDividerLeft, 0,
+                            expectedMiddleDividerLeft + expectedDividerSize,
+                            expectedDividerPadding),
+                    Color.YELLOW, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of bottom padding of middle divider is yellow",
+                    parent,
+                    new Rect(expectedMiddleDividerLeft, parentHeight - expectedDividerPadding,
+                            expectedMiddleDividerLeft + expectedDividerSize, parentHeight),
+                    Color.YELLOW, 1, true);
+        }
+
+        // Do we expect right divider?
+        if (expectingRightDivider) {
+            final int expectedRightDividerLeft = expectedRightChildRight;
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of right divider is " +
+                            TestUtils.formatColorToHex(expectedDividerColor),
+                    parent,
+                    new Rect(expectedRightDividerLeft, expectedDividerPadding,
+                            expectedRightDividerLeft + expectedDividerSize,
+                            parentHeight - expectedDividerPadding),
+                    expectedDividerColor, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of top padding of right divider is yellow",
+                    parent,
+                    new Rect(expectedRightDividerLeft, 0,
+                            expectedRightDividerLeft + expectedDividerSize,
+                            expectedDividerPadding),
+                    Color.YELLOW, 1, true);
+            TestUtils.assertRegionPixelsOfColor(
+                    "Region of bottom padding of right divider is yellow",
+                    parent,
+                    new Rect(expectedRightDividerLeft, parentHeight - expectedDividerPadding,
+                            expectedRightDividerLeft + expectedDividerSize, parentHeight),
+                    Color.YELLOW, 1, true);
+        }
+    }
+
+    /**
+     * layout of horizontal LinearLayout.
+     * -----------------------------------
+     * | ------------  |  -------------  |
+     * | |          |     |           |  |
+     * | |          |  d  |           |  |
+     * | |          |  i  |           |  |
+     * | |          |  v  |           |  |
+     * | |  child1  |  i  |  child2   |  |
+     * | |          |  d  |           |  |
+     * | |          |  e  |           |  |
+     * | |          |  r  |           |  |
+     * | |          |     |           |  |
+     * | ------------  |  -------------  |
+     * -----------------------------------
+     *
+     * Parent is filled with yellow color. Child 1 is filled with green and child 2 is filled
+     * with blue. Divider is red at the beginning. Throughout this method we reconfigure the
+     * visibility, drawable and paddings of the divider and verify the overall visuals of the
+     * container.
+     */
+    public void testDividersInHorizontalLayout() {
+        final LinearLayout parent =
+                (LinearLayout) mActivity.findViewById(R.id.horizontal_with_divider);
+
+        final Instrumentation instrumentation = getInstrumentation();
+
+        instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        instrumentation.waitForIdleSync();
+
+        final Resources res = mActivity.getResources();
+        final int dividerSize = res.getDimensionPixelSize(R.dimen.linear_layout_divider_size);
+        final int dividerPadding = res.getDimensionPixelSize(R.dimen.linear_layout_divider_padding);
+
+        assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE, parent.getShowDividers());
+        assertEquals(dividerPadding, parent.getDividerPadding());
+        final Drawable dividerDrawable = parent.getDividerDrawable();
+        TestUtils.assertAllPixelsOfColor("Divider is red", dividerDrawable,
+                dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
+                false, Color.RED, 1, true);
+
+        // Test the initial visuals of the entire parent
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Change the divider to magenta
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerDrawable(
+                        mActivity.getDrawable(R.drawable.linear_layout_divider_magenta)));
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.MAGENTA, dividerPadding);
+
+        // Change the divider to null (no divider effectively)
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerDrawable(null));
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                0, Color.TRANSPARENT, 0);
+
+        // Change the divider back to red
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerDrawable(
+                        mActivity.getDrawable(R.drawable.linear_layout_divider_red)));
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Change the padding to half the original size
+        final int halfPadding = dividerPadding / 2;
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerPadding(halfPadding));
+        assertEquals(halfPadding, parent.getDividerPadding());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, halfPadding);
+
+        // Change the padding to twice the original size
+        final int doublePadding = dividerPadding * 2;
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerPadding(doublePadding));
+        assertEquals(doublePadding, parent.getDividerPadding());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, doublePadding);
+
+        // And back to the original padding
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setDividerPadding(dividerPadding));
+        assertEquals(dividerPadding, parent.getDividerPadding());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Set show dividers to NONE (no divider effectively)
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE));
+        assertEquals(LinearLayout.SHOW_DIVIDER_NONE, parent.getShowDividers());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_NONE,
+                0, Color.TRANSPARENT, 0);
+
+        // Show only left divider
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING));
+        assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING, parent.getShowDividers());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_BEGINNING,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show only right divider
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_END));
+        assertEquals(LinearLayout.SHOW_DIVIDER_END, parent.getShowDividers());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_END,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show left and right dividers
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(
+                        LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END));
+        assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
+                parent.getShowDividers());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent,
+                LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show left and middle dividers
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(
+                        LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE));
+        assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
+                parent.getShowDividers());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent,
+                LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show middle and right dividers
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(
+                        LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END));
+        assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
+                parent.getShowDividers());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent,
+                LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
+                dividerSize, Color.RED, dividerPadding);
+
+        // Show left, middle and right dividers
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+                () -> parent.setShowDividers(
+                        LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+                                | LinearLayout.SHOW_DIVIDER_END));
+        assertEquals(
+                LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+                        | LinearLayout.SHOW_DIVIDER_END,
+                parent.getShowDividers());
+        verifyVisualsOfHorizontalLayoutWithDivider(parent,
+                LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+                        | LinearLayout.SHOW_DIVIDER_END,
+                dividerSize, Color.RED, dividerPadding);
+    }
+
     private class MockListView extends ListView {
         private final static int DEFAULT_CHILD_BASE_LINE = 1;
 
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java
index 4f36e94..d936984 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java
@@ -16,17 +16,16 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.content.res.XmlResourceParser;
 import android.test.AndroidTestCase;
+import android.view.Gravity;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.LinearLayout;
 import android.widget.cts.util.XmlUtils;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
 public class LinearLayout_LayoutParamsTest extends AndroidTestCase {
@@ -34,17 +33,47 @@
         XmlResourceParser p = mContext.getResources().getLayout(R.layout.linearlayout_layout);
 
         XmlUtils.beginDocument(p, "LinearLayout");
-        new LinearLayout.LayoutParams(getContext(), p);
+        LinearLayout.LayoutParams linearLayoutParams =
+                new LinearLayout.LayoutParams(getContext(), p);
+        assertEquals(LayoutParams.MATCH_PARENT, linearLayoutParams.width);
+        assertEquals(LayoutParams.WRAP_CONTENT, linearLayoutParams.height);
+        assertEquals(0.0f, linearLayoutParams.weight);
+        assertEquals(-1, linearLayoutParams.gravity);
 
-        new LinearLayout.LayoutParams(320, 240);
+        linearLayoutParams = new LinearLayout.LayoutParams(320, 240);
+        assertEquals(320, linearLayoutParams.width);
+        assertEquals(240, linearLayoutParams.height);
+        assertEquals(0.0f, linearLayoutParams.weight);
+        assertEquals(-1, linearLayoutParams.gravity);
 
-        new LinearLayout.LayoutParams(320, 240, 0);
+        linearLayoutParams = new LinearLayout.LayoutParams(360, 320, 0.4f);
+        assertEquals(360, linearLayoutParams.width);
+        assertEquals(320, linearLayoutParams.height);
+        assertEquals(0.4f, linearLayoutParams.weight);
+        assertEquals(-1, linearLayoutParams.gravity);
 
-        LayoutParams layoutParams = new LayoutParams(320, 480);
-        new LinearLayout.LayoutParams(layoutParams);
+        LayoutParams layoutParams = new LayoutParams(200, 480);
+        linearLayoutParams = new LinearLayout.LayoutParams(layoutParams);
+        assertEquals(200, linearLayoutParams.width);
+        assertEquals(480, linearLayoutParams.height);
+        assertEquals(0.0f, linearLayoutParams.weight);
+        assertEquals(-1, linearLayoutParams.gravity);
 
-        MarginLayoutParams marginLayoutParams = new MarginLayoutParams(320, 480);
-        new LinearLayout.LayoutParams(marginLayoutParams);
+        MarginLayoutParams marginLayoutParams = new MarginLayoutParams(320, 200);
+        linearLayoutParams = new LinearLayout.LayoutParams(marginLayoutParams);
+        assertEquals(320, linearLayoutParams.width);
+        assertEquals(200, linearLayoutParams.height);
+        assertEquals(0.0f, linearLayoutParams.weight);
+        assertEquals(-1, linearLayoutParams.gravity);
+
+        LinearLayout.LayoutParams linearLayoutParams2 = new LinearLayout.LayoutParams(360, 720);
+        linearLayoutParams2.weight = 0.9f;
+        linearLayoutParams2.gravity = Gravity.RIGHT;
+        linearLayoutParams = new LinearLayout.LayoutParams(linearLayoutParams2);
+        assertEquals(360, linearLayoutParams.width);
+        assertEquals(720, linearLayoutParams.height);
+        assertEquals(0.9f, linearLayoutParams.weight);
+        assertEquals(Gravity.RIGHT, linearLayoutParams.gravity);
     }
 
     public void testDebug() {
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index b50f8c9..8848e99 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -16,14 +16,17 @@
 
 package android.widget.cts;
 
+import static org.mockito.Mockito.*;
+
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.KeyEventUtil;
+import android.cts.util.CtsKeyEventUtil;
+import android.cts.util.CtsTouchUtils;
+import android.cts.util.WidgetTestUtils;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.InstrumentationRegistry;
 import android.test.ActivityInstrumentationTestCase2;
@@ -32,7 +35,6 @@
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -43,16 +45,12 @@
 import android.widget.ListView;
 import android.widget.PopupWindow;
 import android.widget.TextView;
-import android.widget.cts.util.ViewTestUtils;
-
-import static org.mockito.Mockito.*;
 
 @SmallTest
 public class ListPopupWindowTest extends
         ActivityInstrumentationTestCase2<ListPopupWindowCtsActivity> {
     private Instrumentation mInstrumentation;
     private Activity mActivity;
-    private KeyEventUtil mKeyEventUtil;
     private Builder mPopupWindowBuilder;
 
     /** The list popup window. */
@@ -86,7 +84,6 @@
         mInstrumentation = getInstrumentation();
         mActivity = getActivity();
         mItemClickListener = new PopupItemClickListener();
-        mKeyEventUtil = new KeyEventUtil(mInstrumentation);
     }
 
     @Override
@@ -105,7 +102,16 @@
 
         new ListPopupWindow(mActivity, null, android.R.attr.popupWindowStyle);
 
+        new ListPopupWindow(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_ListPopupWindow);
+
+        new ListPopupWindow(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_ListPopupWindow);
+
         new ListPopupWindow(mActivity, null, 0, android.R.style.Widget_Material_ListPopupWindow);
+
+        new ListPopupWindow(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_ListPopupWindow);
     }
 
     public void testNoDefaultVisibility() {
@@ -358,7 +364,7 @@
                 mPopupWindow.getSoftInputMode());
     }
 
-    private void verifyDismissalViaTouch(boolean setupAsModal) throws Throwable {
+    private void verifyDismissalViaTouch(boolean setupAsModal) {
         // Register a click listener on the top-level container
         final View mainContainer = mActivity.findViewById(R.id.main_container);
         View.OnClickListener mockContainerClickListener = mock(View.OnClickListener.class);
@@ -372,49 +378,20 @@
         // Make sure that the modality of the popup window is set up correctly
         assertEquals("Popup window modality", setupAsModal, mPopupWindow.isModal());
 
-        // Determine the location of the popup on the screen so that we can emulate
-        // a tap outside of its bounds to dismiss it
-        final int[] popupOnScreenXY = new int[2];
-        final Rect rect = new Rect();
-        mPopupWindow.getListView().getLocationOnScreen(popupOnScreenXY);
-        mPopupWindow.getBackground().getPadding(rect);
-
-        int emulatedTapX = popupOnScreenXY[0] - rect.left - 20;
-        int emulatedTapY = popupOnScreenXY[1] + mPopupWindow.getListView().getHeight() +
-                rect.top + rect.bottom + 20;
-
         // The logic below uses Instrumentation to emulate a tap outside the bounds of the
         // displayed list popup window. This tap is then treated by the framework to be "split" as
         // the ACTION_OUTSIDE for the popup itself, as well as DOWN / MOVE / UP for the underlying
         // view root if the popup is not modal.
         // It is not correct to emulate these two sequences separately in the test, as it
-        // wouldn't emulate the user-facing interaction for this test. Note that usage
-        // of Instrumentation is necessary here since Espresso's actions operate at the level
-        // of view or data. Also, we don't want to use View.dispatchTouchEvent directly as
-        // that would require emulation of two separate sequences as well.
-
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-
-        // Inject DOWN event
-        long downTime = SystemClock.uptimeMillis();
-        MotionEvent eventDown = MotionEvent.obtain(
-                downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
-        instrumentation.sendPointerSync(eventDown);
-
-        // Inject MOVE event
-        long moveTime = SystemClock.uptimeMillis();
-        MotionEvent eventMove = MotionEvent.obtain(
-                moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedTapX, emulatedTapY, 1);
-        instrumentation.sendPointerSync(eventMove);
-
-        // Inject UP event
-        long upTime = SystemClock.uptimeMillis();
-        MotionEvent eventUp = MotionEvent.obtain(
-                upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
-        instrumentation.sendPointerSync(eventUp);
-
-        // Wait for the system to process all events in the queue
-        instrumentation.waitForIdleSync();
+        // wouldn't emulate the user-facing interaction for this test. Also, we don't want to use
+        // View.dispatchTouchEvent directly as that would require emulation of two separate
+        // sequences as well.
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final ListView popupListView = mPopupWindow.getListView();
+        final Rect rect = new Rect();
+        mPopupWindow.getBackground().getPadding(rect);
+        CtsTouchUtils.emulateTapOnScreen(instrumentation, popupListView,
+                -rect.left - 20, popupListView.getHeight() + rect.top + rect.bottom + 20);
 
         // At this point our popup should not be showing and should have notified its
         // dismiss listener
@@ -426,19 +403,19 @@
         verify(mockContainerClickListener, times(setupAsModal ? 0 : 1)).onClick(mainContainer);
     }
 
-    public void testDismissalOutsideNonModal() throws Throwable {
+    public void testDismissalOutsideNonModal() {
         verifyDismissalViaTouch(false);
     }
 
-    public void testDismissalOutsideModal() throws Throwable {
+    public void testDismissalOutsideModal() {
         verifyDismissalViaTouch(true);
     }
 
-    public void testItemClicks() throws Throwable {
+    public void testItemClicks() {
         mPopupWindowBuilder = new Builder().withItemClickListener().withDismissListener();
         mPopupWindowBuilder.show();
 
-        runTestOnUiThread(() -> mPopupWindow.performItemClick(2));
+        mInstrumentation.runOnMainSync(() -> mPopupWindow.performItemClick(2));
         mInstrumentation.waitForIdleSync();
 
         verify(mPopupWindowBuilder.mOnItemClickListener, times(1)).onItemClick(
@@ -448,7 +425,8 @@
         verify(mPopupWindowBuilder.mOnDismissListener, times(1)).onDismiss();
 
         mPopupWindowBuilder.showAgain();
-        runTestOnUiThread(() -> mPopupWindow.getListView().performItemClick(null, 1, 1));
+        mInstrumentation.runOnMainSync(
+                () -> mPopupWindow.getListView().performItemClick(null, 1, 1));
         mInstrumentation.waitForIdleSync();
 
         verify(mPopupWindowBuilder.mOnItemClickListener, times(1)).onItemClick(
@@ -461,7 +439,7 @@
         verifyNoMoreInteractions(mPopupWindowBuilder.mOnItemClickListener);
     }
 
-    public void testPromptViewAbove() throws Throwable {
+    public void testPromptViewAbove() {
         final View promptView = LayoutInflater.from(mActivity).inflate(
                 R.layout.popupwindow_prompt, null);
         mPopupWindowBuilder = new Builder().withPrompt(
@@ -477,7 +455,7 @@
         promptView.getLocationOnScreen(promptViewOnScreenXY);
 
         final ListView listView = mPopupWindow.getListView();
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
 
         final View firstListChild = listView.getChildAt(0);
         final int[] firstChildOnScreenXY = new int[2];
@@ -486,7 +464,7 @@
         assertTrue(promptViewOnScreenXY[1] + promptView.getHeight() <= firstChildOnScreenXY[1]);
     }
 
-    public void testPromptViewBelow() throws Throwable {
+    public void testPromptViewBelow() {
         final View promptView = LayoutInflater.from(mActivity).inflate(
                 R.layout.popupwindow_prompt, null);
         mPopupWindowBuilder = new Builder().withPrompt(
@@ -499,7 +477,7 @@
         assertEquals(ListPopupWindow.POSITION_PROMPT_BELOW, mPopupWindow.getPromptPosition());
 
         final ListView listView = mPopupWindow.getListView();
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
 
         final int[] promptViewOnScreenXY = new int[2];
         promptView.getLocationOnScreen(promptViewOnScreenXY);
@@ -512,14 +490,14 @@
     }
 
     @Presubmit
-    public void testAccessSelection() throws Throwable {
+    public void testAccessSelection() {
         mPopupWindowBuilder = new Builder().withItemSelectedListener();
         mPopupWindowBuilder.show();
 
         final ListView listView = mPopupWindow.getListView();
 
         // Select an item
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
                 () -> mPopupWindow.setSelection(1));
 
         // And verify the current selection state + selection listener invocation
@@ -534,7 +512,7 @@
                 ((TextView) selectedView.findViewById(android.R.id.text1)).getText());
 
         // Select another item
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
                 () -> mPopupWindow.setSelection(3));
 
         // And verify the new selection state + selection listener invocation
@@ -549,8 +527,8 @@
                 ((TextView) selectedView.findViewById(android.R.id.text1)).getText());
 
         // Clear selection
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
-                () -> mPopupWindow.clearListSelection());
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+                mPopupWindow::clearListSelection);
 
         // And verify empty selection state + no more selection listener invocation
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onNothingSelected(
@@ -562,7 +540,7 @@
         verifyNoMoreInteractions(mPopupWindowBuilder.mOnItemSelectedListener);
     }
 
-    public void testNoDefaultDismissalWithBackButton() throws Throwable {
+    public void testNoDefaultDismissalWithBackButton() {
         mPopupWindowBuilder = new Builder().withDismissListener();
         mPopupWindowBuilder.show();
 
@@ -574,7 +552,7 @@
         assertTrue(mPopupWindow.isShowing());
     }
 
-    public void testCustomDismissalWithBackButton() throws Throwable {
+    public void testCustomDismissalWithBackButton() {
         mPopupWindowBuilder = new Builder().withAnchor(R.id.anchor_upper_left)
                 .withDismissListener();
         mPopupWindowBuilder.show();
@@ -584,7 +562,7 @@
                 (MockViewForListPopupWindow) mPopupWindow.getAnchorView();
         anchor.wireTo(mPopupWindow);
         // Request focus on our EditText
-        runTestOnUiThread(() -> anchor.requestFocus());
+        mInstrumentation.runOnMainSync(anchor::requestFocus);
         mInstrumentation.waitForIdleSync();
         assertTrue(anchor.isFocused());
 
@@ -596,7 +574,7 @@
         assertFalse(mPopupWindow.isShowing());
     }
 
-    public void testListSelectionWithDPad() throws Throwable {
+    public void testListSelectionWithDPad() {
         mPopupWindowBuilder = new Builder().withAnchor(R.id.anchor_upper_left)
                 .withDismissListener().withItemSelectedListener();
         mPopupWindowBuilder.show();
@@ -608,13 +586,13 @@
                 (MockViewForListPopupWindow) mPopupWindow.getAnchorView();
         anchor.wireTo(mPopupWindow);
         // Request focus on our EditText
-        runTestOnUiThread(() -> anchor.requestFocus());
+        mInstrumentation.runOnMainSync(anchor::requestFocus);
         mInstrumentation.waitForIdleSync();
         assertTrue(anchor.isFocused());
 
         // Select entry #1 in the popup list
         final ListView listView = mPopupWindow.getListView();
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
                 () -> mPopupWindow.setSelection(1));
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
                 any(AdapterView.class), any(View.class), eq(1), eq(1L));
@@ -622,10 +600,10 @@
         // Send DPAD_DOWN key event. As our custom extension of EditText calls
         // ListPopupWindow.onKeyDown and onKeyUp, the end result should be transfer of selection
         // down one row
-        mKeyEventUtil.sendKeyDownUp(listView, KeyEvent.KEYCODE_DPAD_DOWN);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, listView, KeyEvent.KEYCODE_DPAD_DOWN);
         mInstrumentation.waitForIdleSync();
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
 
         // At this point we expect that item #2 was selected
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
@@ -634,10 +612,10 @@
         // Send a DPAD_UP key event. As our custom extension of EditText calls
         // ListPopupWindow.onKeyDown and onKeyUp, the end result should be transfer of selection
         // up one row
-        mKeyEventUtil.sendKeyDownUp(listView, KeyEvent.KEYCODE_DPAD_UP);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, listView, KeyEvent.KEYCODE_DPAD_UP);
         mInstrumentation.waitForIdleSync();
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
 
         // At this point we expect that item #1 was selected
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(2)).onItemSelected(
@@ -646,10 +624,10 @@
         // Send one more DPAD_UP key event. As our custom extension of EditText calls
         // ListPopupWindow.onKeyDown and onKeyUp, the end result should be transfer of selection
         // up one more row
-        mKeyEventUtil.sendKeyDownUp(listView, KeyEvent.KEYCODE_DPAD_UP);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, listView, KeyEvent.KEYCODE_DPAD_UP);
         mInstrumentation.waitForIdleSync();
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
 
         // At this point we expect that item #0 was selected
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
@@ -658,7 +636,7 @@
         // Send ENTER key event. As our custom extension of EditText calls
         // ListPopupWindow.onKeyDown and onKeyUp, the end result should be dismissal of
         // the popup window
-        mKeyEventUtil.sendKeyDownUp(listView, KeyEvent.KEYCODE_ENTER);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation,listView, KeyEvent.KEYCODE_ENTER);
         mInstrumentation.waitForIdleSync();
 
         verify(mPopupWindowBuilder.mOnDismissListener, times(1)).onDismiss();
@@ -668,41 +646,7 @@
         verifyNoMoreInteractions(mPopupWindowBuilder.mOnDismissListener);
     }
 
-    /**
-     * Emulates a drag-down gestures by injecting ACTION events with {@link Instrumentation}.
-     */
-    private void emulateDragDownGesture(int emulatedX, int emulatedStartY, int swipeAmount) {
-        // The logic below uses Instrumentation to emulate a swipe / drag gesture to bring up
-        // the popup content.
-
-        // Inject DOWN event
-        long downTime = SystemClock.uptimeMillis();
-        MotionEvent eventDown = MotionEvent.obtain(
-                downTime, downTime, MotionEvent.ACTION_DOWN, emulatedX, emulatedStartY, 1);
-        mInstrumentation.sendPointerSync(eventDown);
-
-        // Inject a sequence of MOVE events that emulate a "swipe down" gesture
-        for (int i = 0; i < 10; i++) {
-            long moveTime = SystemClock.uptimeMillis();
-            final int moveY = emulatedStartY + swipeAmount * i / 10;
-            MotionEvent eventMove = MotionEvent.obtain(
-                    moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedX, moveY, 1);
-            mInstrumentation.sendPointerSync(eventMove);
-            // sleep for a bit to emulate a 200ms swipe
-            SystemClock.sleep(20);
-        }
-
-        // Inject UP event
-        long upTime = SystemClock.uptimeMillis();
-        MotionEvent eventUp = MotionEvent.obtain(
-                upTime, upTime, MotionEvent.ACTION_UP, emulatedX, emulatedStartY + swipeAmount, 1);
-        mInstrumentation.sendPointerSync(eventUp);
-
-        // Wait for the system to process all events in the queue
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testCreateOnDragListener() throws Throwable {
+    public void testCreateOnDragListener() {
         // In this test we want precise control over the height of the popup content since
         // we need to know by how much to swipe down to end the emulated gesture over the
         // specific item in the popup. This is why we're using a popup style that removes
@@ -738,7 +682,8 @@
         int swipeAmount = 2 * popupRowHeight;
 
         // Emulate drag-down gesture with a sequence of motion events
-        emulateDragDownGesture(emulatedX, emulatedStartY, swipeAmount);
+        CtsTouchUtils.emulateDragGesture(getInstrumentation(), emulatedX, emulatedStartY,
+                0, swipeAmount);
 
         // We expect the swipe / drag gesture to result in clicking the second item in our list.
         verify(mPopupWindowBuilder.mOnItemClickListener, times(1)).onItemClick(
@@ -952,7 +897,8 @@
             if (mHasItemSelectedListener) {
                 mOnItemSelectedListener = mock(AdapterView.OnItemSelectedListener.class);
                 mPopupWindow.setOnItemSelectedListener(mOnItemSelectedListener);
-                mPopupWindow.setListSelector(mActivity.getDrawable(R.drawable.red_fill));
+                mPopupWindow.setListSelector(
+                        mActivity.getDrawable(R.drawable.red_translucent_fill));
             }
 
             if (mHasDismissListener) {
diff --git a/tests/tests/widget/src/android/widget/cts/ListViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ListViewCtsActivity.java
index ce198b3..1d1b42f 100644
--- a/tests/tests/widget/src/android/widget/cts/ListViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ListViewCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 public class ListViewCtsActivity extends Activity {
     @Override
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/ListViewFixedCtsActivity.java
similarity index 76%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/ListViewFixedCtsActivity.java
index 481f5be..f34a452 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ListViewFixedCtsActivity.java
@@ -14,17 +14,15 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
 
-public class SlowCreateActivity extends Activity {
+public class ListViewFixedCtsActivity extends Activity {
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.listviewfixed_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ListViewTest.java b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
index 41fb14b..4324314 100644
--- a/tests/tests/widget/src/android/widget/cts/ListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
@@ -16,23 +16,25 @@
 
 package android.widget.cts;
 
-import junit.framework.Assert;
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.mockito.Mockito.*;
 
 import android.app.ActionBar.LayoutParams;
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.cts.util.PollingCheck;
+import android.cts.util.WidgetTestUtils;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Parcelable;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Pair;
 import android.util.SparseArray;
@@ -43,48 +45,50 @@
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
 import android.view.animation.LayoutAnimationController;
+import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.FrameLayout;
-import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
-import android.widget.cts.R;
-import android.widget.cts.util.ViewTestUtils;
+import android.widget.cts.util.TestUtils;
+
+import junit.framework.Assert;
+
+import org.xmlpull.v1.XmlPullParser;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyLong;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
+@SmallTest
 public class ListViewTest extends ActivityInstrumentationTestCase2<ListViewCtsActivity> {
     private final String[] mCountryList = new String[] {
         "Argentina", "Australia", "China", "France", "Germany", "Italy", "Japan", "United States"
     };
+    private final String[] mLongCountryList = new String[] {
+        "Argentina", "Australia", "Belize", "Botswana", "Brazil", "Cameroon", "China", "Cyprus",
+        "Denmark", "Djibouti", "Ethiopia", "Fiji", "Finland", "France", "Gabon", "Germany",
+        "Ghana", "Haiti", "Honduras", "Iceland", "India", "Indonesia", "Ireland", "Italy",
+        "Japan", "Kiribati", "Laos", "Lesotho", "Liberia", "Malaysia", "Mongolia", "Myanmar",
+        "Nauru", "Norway", "Oman", "Pakistan", "Philippines", "Portugal", "Romania", "Russia",
+        "Rwanda", "Singapore", "Slovakia", "Slovenia", "Somalia", "Swaziland", "Togo", "Tuvalu",
+        "Uganda", "Ukraine", "United States", "Vanuatu", "Venezuela", "Zimbabwe"
+    };
     private final String[] mNameList = new String[] {
         "Jacky", "David", "Kevin", "Michael", "Andy"
     };
-    private final String[] mEmptyList = new String[0];
 
     private ListView mListView;
     private Activity mActivity;
     private Instrumentation mInstrumentation;
     private AttributeSet mAttributeSet;
     private ArrayAdapter<String> mAdapter_countries;
+    private ArrayAdapter<String> mAdapter_longCountries;
     private ArrayAdapter<String> mAdapter_names;
-    private ArrayAdapter<String> mAdapter_empty;
 
     public ListViewTest() {
         super("android.widget.cts", ListViewCtsActivity.class);
@@ -98,12 +102,12 @@
         XmlPullParser parser = mActivity.getResources().getXml(R.layout.listview_layout);
         mAttributeSet = Xml.asAttributeSet(parser);
 
-        mAdapter_countries = new ArrayAdapter<String>(mActivity,
+        mAdapter_countries = new ArrayAdapter<>(mActivity,
                 android.R.layout.simple_list_item_1, mCountryList);
-        mAdapter_names = new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1,
+        mAdapter_longCountries = new ArrayAdapter<>(mActivity,
+                android.R.layout.simple_list_item_1, mLongCountryList);
+        mAdapter_names = new ArrayAdapter<>(mActivity, android.R.layout.simple_list_item_1,
                 mNameList);
-        mAdapter_empty = new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1,
-                mEmptyList);
 
         mListView = (ListView) mActivity.findViewById(R.id.listview_default);
     }
@@ -136,40 +140,40 @@
     }
 
     public void testGetMaxScrollAmount() {
-        setAdapter(mAdapter_empty);
-        int scrollAmount = mListView.getMaxScrollAmount();
-        assertEquals(0, scrollAmount);
-
         setAdapter(mAdapter_names);
-        scrollAmount = mListView.getMaxScrollAmount();
+        int scrollAmount = mListView.getMaxScrollAmount();
         assertTrue(scrollAmount > 0);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mListView.getLayoutParams().height = 0;
+            mListView.requestLayout();
+        });
+        PollingCheck.waitFor(() -> mListView.getHeight() == 0);
+
+        scrollAmount = mListView.getMaxScrollAmount();
+        assertEquals(0, scrollAmount);
     }
 
     private void setAdapter(final ArrayAdapter<String> adapter) {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(adapter));
     }
 
     public void testAccessDividerHeight() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
         Drawable d = mListView.getDivider();
         final Rect r = d.getBounds();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return r.bottom - r.top > 0;
-            }
-        }.run();
+        PollingCheck.waitFor(() -> r.bottom - r.top > 0);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setDividerHeight(20));
 
         assertEquals(20, mListView.getDividerHeight());
         assertEquals(20, r.bottom - r.top);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setDividerHeight(10));
 
         assertEquals(10, mListView.getDividerHeight());
@@ -187,13 +191,13 @@
     }
 
     public void testAccessAdapter() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
         assertSame(mAdapter_countries, mListView.getAdapter());
         assertEquals(mCountryList.length, mListView.getCount());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(mAdapter_names));
 
         assertSame(mAdapter_names, mListView.getAdapter());
@@ -280,25 +284,31 @@
         footerView2.setText("footerview2");
 
         mInstrumentation.runOnMainSync(() -> mListView.setFooterDividersEnabled(true));
+        assertTrue(mListView.areFooterDividersEnabled());
         assertEquals(0, mListView.getFooterViewsCount());
 
         mInstrumentation.runOnMainSync(() -> mListView.addFooterView(footerView1, null, true));
+        assertTrue(mListView.areFooterDividersEnabled());
         assertEquals(1, mListView.getFooterViewsCount());
 
-        mInstrumentation.runOnMainSync(() -> mListView.addFooterView(footerView2));
-
-        mInstrumentation.waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> {
+            mListView.setFooterDividersEnabled(false);
+            mListView.addFooterView(footerView2);
+        });
+        assertFalse(mListView.areFooterDividersEnabled());
         assertEquals(2, mListView.getFooterViewsCount());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.removeFooterView(footerView1));
+        assertFalse(mListView.areFooterDividersEnabled());
         assertEquals(1, mListView.getFooterViewsCount());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.removeFooterView(footerView2));
+        assertFalse(mListView.areFooterDividersEnabled());
         assertEquals(0, mListView.getFooterViewsCount());
     }
 
@@ -307,18 +317,28 @@
         final TextView headerView2 = (TextView) mActivity.findViewById(R.id.headerview2);
 
         mInstrumentation.runOnMainSync(() -> mListView.setHeaderDividersEnabled(true));
+        assertTrue(mListView.areHeaderDividersEnabled());
         assertEquals(0, mListView.getHeaderViewsCount());
 
         mInstrumentation.runOnMainSync(() -> mListView.addHeaderView(headerView2, null, true));
+        assertTrue(mListView.areHeaderDividersEnabled());
         assertEquals(1, mListView.getHeaderViewsCount());
 
-        mInstrumentation.runOnMainSync(() -> mListView.addHeaderView(headerView1));
+        mInstrumentation.runOnMainSync(() -> {
+            mListView.setHeaderDividersEnabled(false);
+            mListView.addHeaderView(headerView1);
+        });
+        assertFalse(mListView.areHeaderDividersEnabled());
         assertEquals(2, mListView.getHeaderViewsCount());
+
+        mInstrumentation.runOnMainSync(() -> mListView.removeHeaderView(headerView2));
+        assertFalse(mListView.areHeaderDividersEnabled());
+        assertEquals(1, mListView.getHeaderViewsCount());
     }
 
     public void testHeaderFooterType() throws Throwable {
         final TextView headerView = new TextView(getActivity());
-        final List<Pair<View, View>> mismatch = new ArrayList<Pair<View, View>>();
+        final List<Pair<View, View>> mismatch = new ArrayList<>();
         final ArrayAdapter adapter = new ArrayAdapter<String>(mActivity,
                 android.R.layout.simple_list_item_1, mNameList) {
             @Override
@@ -331,7 +351,7 @@
             public View getView(int position, View convertView, ViewGroup parent) {
                 if (position == 0) {
                     if (convertView != null && convertView != headerView) {
-                        mismatch.add(new Pair<View, View>(headerView, convertView));
+                        mismatch.add(new Pair<>(headerView, convertView));
                     }
                     return headerView;
                 } else {
@@ -344,57 +364,52 @@
                 return super.getCount() + 1;
             }
         };
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(adapter));
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
-                () -> adapter.notifyDataSetChanged());
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                adapter::notifyDataSetChanged);
 
         assertEquals(0, mismatch.size());
     }
 
     public void testAccessDivider() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
         Drawable defaultDrawable = mListView.getDivider();
         final Rect r = defaultDrawable.getBounds();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return r.bottom - r.top > 0;
-            }
-        }.run();
+        PollingCheck.waitFor(() -> r.bottom - r.top > 0);
 
         final Drawable d = mActivity.getResources().getDrawable(R.drawable.scenery);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setDivider(d));
         assertSame(d, mListView.getDivider());
         assertEquals(d.getBounds().height(), mListView.getDividerHeight());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setDividerHeight(10));
         assertEquals(10, mListView.getDividerHeight());
         assertEquals(10, d.getBounds().height());
     }
 
     public void testSetSelection() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setSelection(1));
         String item = (String) mListView.getSelectedItem();
         assertEquals(mCountryList[1], item);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setSelectionFromTop(5, 0));
         item = (String) mListView.getSelectedItem();
         assertEquals(mCountryList[5], item);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
-                () -> mListView.setSelectionAfterHeaderView());
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                mListView::setSelectionAfterHeaderView);
         item = (String) mListView.getSelectedItem();
         assertEquals(mCountryList[0], item);
     }
@@ -404,11 +419,11 @@
     }
 
     public void testPerformItemClick() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
         mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setSelection(2));
 
         final TextView child = (TextView) mAdapter_countries.getView(2, null, mListView);
@@ -432,30 +447,46 @@
         verifyNoMoreInteractions(onClickListener);
     }
 
-    public void testSaveAndRestoreInstanceState() {
-        // implementation details, do NOT test
+    public void testSaveAndRestoreInstanceState_positionIsRestored() {
+        ListView listView = new ListView(mActivity);
+        listView.setAdapter(mAdapter_countries);
+        assertEquals(0, listView.getSelectedItemPosition());
+
+        int positionToTest = mAdapter_countries.getCount() - 1;
+        listView.setSelection(positionToTest);
+        assertEquals(positionToTest, listView.getSelectedItemPosition());
+        Parcelable savedState = listView.onSaveInstanceState();
+
+        listView.setSelection(positionToTest - 1);
+        assertEquals(positionToTest - 1, listView.getSelectedItemPosition());
+
+        listView.onRestoreInstanceState(savedState);
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
+        listView.measure(measureSpec,measureSpec);
+        listView.layout(0, 0, 100, 100);
+        assertEquals(positionToTest, listView.getSelectedItemPosition());
     }
 
     public void testDispatchKeyEvent() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> {
                     mListView.setAdapter(mAdapter_countries);
                     mListView.requestFocus();
                 });
         assertTrue(mListView.hasFocus());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setSelection(1));
         String item = (String) mListView.getSelectedItem();
         assertEquals(mCountryList[1], item);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () ->  {
                     KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
                     mListView.dispatchKeyEvent(keyEvent);
                 });
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> {
                     KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
                             KeyEvent.KEYCODE_DPAD_DOWN);
@@ -468,7 +499,7 @@
     }
 
     public void testRequestChildRectangleOnScreen() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
         TextView child = (TextView) mAdapter_countries.getView(0, null, mListView);
@@ -588,7 +619,7 @@
         ListView listView = new ListView(mActivity);
         List<String> items = new ArrayList<>();
         items.add("hello");
-        Adapter<String> adapter = new Adapter<String>(mActivity, 0, items);
+        Adapter<String> adapter = new Adapter<>(mActivity, 0, items);
         listView.setAdapter(adapter);
 
         int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
@@ -613,7 +644,7 @@
         listView.addHeaderView(new View(mActivity), null, false);
         List<String> items = new ArrayList<>();
         items.add("hello");
-        Adapter<String> adapter = new Adapter<String>(mActivity, 0, items);
+        Adapter<String> adapter = new Adapter<>(mActivity, 0, items);
         listView.setAdapter(adapter);
 
         listView.setSelection(1);
@@ -634,13 +665,13 @@
     @MediumTest
     public void testFullDetachHeaderViewOnScroll() {
         final AttachDetachAwareView header = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setAdapter(new DummyAdapter(1000));
             mListView.addHeaderView(header);
         });
         assertEquals("test sanity", 1, header.mOnAttachCount);
         assertEquals("test sanity", 0, header.mOnDetachCount);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.scrollListBy(mListView.getHeight() * 3);
         });
         assertNull("test sanity, header should be removed", header.getParent());
@@ -651,13 +682,13 @@
     @MediumTest
     public void testFullDetachHeaderViewOnRelayout() {
         final AttachDetachAwareView header = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setAdapter(new DummyAdapter(1000));
             mListView.addHeaderView(header);
         });
         assertEquals("test sanity", 1, header.mOnAttachCount);
         assertEquals("test sanity", 0, header.mOnDetachCount);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setSelection(800);
         });
         assertNull("test sanity, header should be removed", header.getParent());
@@ -668,7 +699,7 @@
     @MediumTest
     public void testFullDetachHeaderViewOnScrollForFocus() {
         final AttachDetachAwareView header = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setAdapter(new DummyAdapter(1000));
             mListView.addHeaderView(header);
         });
@@ -677,7 +708,7 @@
         while(header.getParent() != null) {
             assertEquals("header view should NOT be detached", 0, header.mOnDetachCount);
             sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-            ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, null);
+            WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, null);
         }
         assertEquals("header view should be detached", 1, header.mOnDetachCount);
         assertFalse(header.isTemporarilyDetached());
@@ -686,18 +717,18 @@
     @MediumTest
     public void testFullyDetachUnusedViewOnScroll() {
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setAdapter(new DummyAdapter(1000, theView));
         });
         assertEquals("test sanity", 1, theView.mOnAttachCount);
         assertEquals("test sanity", 0, theView.mOnDetachCount);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.scrollListBy(mListView.getHeight() * 2);
         });
         assertNull("test sanity, unused view should be removed", theView.getParent());
         assertEquals("unused view should be detached", 1, theView.mOnDetachCount);
         assertFalse(theView.isTemporarilyDetached());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.scrollListBy(-mListView.getHeight() * 2);
             // listview limits scroll to 1 page which is why we call it twice here.
             mListView.scrollListBy(-mListView.getHeight() * 2);
@@ -711,18 +742,18 @@
     @MediumTest
     public void testFullyDetachUnusedViewOnReLayout() {
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setAdapter(new DummyAdapter(1000, theView));
         });
         assertEquals("test sanity", 1, theView.mOnAttachCount);
         assertEquals("test sanity", 0, theView.mOnDetachCount);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setSelection(800);
         });
         assertNull("test sanity, unused view should be removed", theView.getParent());
         assertEquals("unused view should be detached", 1, theView.mOnDetachCount);
         assertFalse(theView.isTemporarilyDetached());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setSelection(0);
         });
         assertNotNull("test sanity, view should be re-added", theView.getParent());
@@ -734,7 +765,7 @@
     @MediumTest
     public void testFullyDetachUnusedViewOnScrollForFocus() {
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setAdapter(new DummyAdapter(1000, theView));
         });
         assertEquals("test sanity", 1, theView.mOnAttachCount);
@@ -742,13 +773,13 @@
         while(theView.getParent() != null) {
             assertEquals("the view should NOT be detached", 0, theView.mOnDetachCount);
             sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-            ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, null);
+            WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, null);
         }
         assertEquals("the view should be detached", 1, theView.mOnDetachCount);
         assertFalse(theView.isTemporarilyDetached());
         while(theView.getParent() == null) {
             sendKeys(KeyEvent.KEYCODE_DPAD_UP);
-            ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, null);
+            WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, null);
         }
         assertEquals("the view should be re-attached", 2, theView.mOnAttachCount);
         assertEquals("the view should not recieve another detach", 1, theView.mOnDetachCount);
@@ -762,19 +793,19 @@
                 ViewGroup.LayoutParams.WRAP_CONTENT));
         view.setMinimumHeight(30);
         final DummyAdapter adapter = new DummyAdapter(2, view);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
-            mListView.setLayoutParams(new LinearLayout.LayoutParams(200, 100));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
+            mListView.setLayoutParams(new FrameLayout.LayoutParams(200, 100));
             mListView.setAdapter(adapter);
         });
         assertEquals("test sanity", 200, mListView.getWidth());
         assertEquals(200, view.getWidth());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setPadding(10, 0, 5, 0);
             assertTrue(view.isLayoutRequested());
         });
         assertEquals(185, view.getWidth());
         assertFalse(view.isLayoutRequested());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setPadding(10, 0, 5, 0);
             assertFalse(view.isLayoutRequested());
         });
@@ -782,17 +813,17 @@
 
     @MediumTest
     public void testResolveRtlOnReAttach() {
-        View spacer = new View(getActivity());
+        View spacer = new View(mActivity);
         spacer.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                 250));
         final DummyAdapter adapter = new DummyAdapter(50, spacer);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
-            mListView.setLayoutParams(new LinearLayout.LayoutParams(200, 150));
+            mListView.setLayoutParams(new FrameLayout.LayoutParams(200, 150));
             mListView.setAdapter(adapter);
         });
         assertEquals("test sanity", 1, mListView.getChildCount());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             // we scroll in pieces because list view caps scroll by its height
             mListView.scrollListBy(100);
             mListView.scrollListBy(100);
@@ -800,14 +831,14 @@
         });
         assertEquals("test sanity", 1, mListView.getChildCount());
         assertEquals("test sanity", 1, mListView.getFirstVisiblePosition());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.scrollListBy(-100);
             mListView.scrollListBy(-100);
             mListView.scrollListBy(-60);
         });
         assertEquals("test sanity", 1, mListView.getChildCount());
         assertEquals("item 0 should be visible", 0, mListView.getFirstVisiblePosition());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
             mListView.scrollListBy(100);
             mListView.scrollListBy(100);
             mListView.scrollListBy(60);
@@ -874,11 +905,12 @@
         assertNotNull(childView2);
 
         // Make sure that the childView1 has focus.
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, childView1, childView1::requestFocus);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, childView1,
+                childView1::requestFocus);
         assertTrue(childView1.isFocused());
 
         // Make sure that ListView#requestLayout() is optimized when nothing is changed.
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, listView::requestLayout);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, listView::requestLayout);
         assertEquals(childView0, listView.getChildAt(0));
         assertEquals(childView1, listView.getChildAt(1));
         assertEquals(childView2, listView.getChildAt(2));
@@ -1048,7 +1080,7 @@
         final ArrayAdapter<String> adapter = new ArrayAdapter<String>(mActivity,
                 android.R.layout.simple_list_item_1, items);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
                 () -> listView.setAdapter(adapter));
 
         final View oldItem = listView.getChildAt(2);
@@ -1056,7 +1088,7 @@
                 .getText();
         oldItem.setHasTransientState(true);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
                 () -> {
                     adapter.remove(adapter.getItem(0));
                     adapter.notifyDataSetChanged();
@@ -1070,28 +1102,27 @@
     }
 
     public void testTransientStateStableIds() throws Exception {
-        final ListView listView = mListView;
-        final ArrayList<String> items = new ArrayList<String>(Arrays.asList(mCountryList));
-        final StableArrayAdapter<String> adapter = new StableArrayAdapter<String>(mActivity,
+        final ArrayList<String> items = new ArrayList<>(Arrays.asList(mCountryList));
+        final StableArrayAdapter<String> adapter = new StableArrayAdapter<>(mActivity,
                 android.R.layout.simple_list_item_1, items);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
-                () -> listView.setAdapter(adapter));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                () -> mListView.setAdapter(adapter));
 
         final Object tag = new Object();
-        final View oldItem = listView.getChildAt(2);
+        final View oldItem = mListView.getChildAt(2);
         final CharSequence oldText = ((TextView) oldItem.findViewById(android.R.id.text1))
                 .getText();
         oldItem.setHasTransientState(true);
         oldItem.setTag(tag);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
                 () -> {
                     adapter.remove(adapter.getItem(0));
                     adapter.notifyDataSetChanged();
                 });
 
-        final View newItem = listView.getChildAt(1);
+        final View newItem = mListView.getChildAt(1);
         final CharSequence newText = ((TextView) newItem.findViewById(android.R.id.text1))
                 .getText();
 
@@ -1115,4 +1146,132 @@
             return true;
         }
     }
+
+    @LargeTest
+    public void testSmoothScrollByOffset() {
+        final int itemCount = mLongCountryList.length;
+
+        mActivity.runOnUiThread(() -> mListView.setAdapter(mAdapter_longCountries));
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(0, mListView.getFirstVisiblePosition());
+
+        // If we're on a really big display, we might be in a situation where the position
+        // we're going to scroll to is already visible. In that case the logic in the rest
+        // of this test will never fire off a listener callback and then fail the test.
+        final int positionToScrollTo = itemCount - 10;
+        final int lastVisiblePosition = mListView.getLastVisiblePosition();
+        if (positionToScrollTo <= lastVisiblePosition) {
+            return;
+        }
+
+        // Register a scroll listener on our ListView. The listener will notify our latch
+        // when the "target" item comes into view. If that never happens, the latch will
+        // time out and fail the test.
+        final CountDownLatch latch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(AbsListView view, int scrollState) {
+            }
+
+            @Override
+            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+                    int totalItemCount) {
+                if ((positionToScrollTo >= firstVisibleItem) &&
+                        (positionToScrollTo <= (firstVisibleItem + visibleItemCount))) {
+                    latch.countDown();
+                }
+            }
+        });
+        int offset = positionToScrollTo - lastVisiblePosition;
+        mActivity.runOnUiThread(() -> mListView.smoothScrollByOffset(offset));
+
+        boolean result = false;
+        try {
+            result = latch.await(20, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Timed out while waiting for the target view to be scrolled into view", result);
+    }
+
+    private static class PositionArrayAdapter<T> extends ArrayAdapter<T> {
+        public PositionArrayAdapter(Context context, int resource, List<T> objects) {
+            super(context, resource, objects);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return true;
+        }
+    }
+
+    public void testGetCheckItemIds() {
+        final ArrayList<String> items = new ArrayList<>(Arrays.asList(mCountryList));
+        final ArrayAdapter<String> adapter = new PositionArrayAdapter<>(mActivity,
+                android.R.layout.simple_list_item_1, items);
+
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                () -> mListView.setAdapter(adapter));
+
+        mInstrumentation.runOnMainSync(
+                () -> mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE));
+        assertTrue(mListView.getCheckItemIds().length == 0);
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, true));
+        TestUtils.assertIdentical(new long[] { 2 }, mListView.getCheckItemIds());
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, true));
+        TestUtils.assertIdentical(new long[] { 2, 4 }, mListView.getCheckItemIds());
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(2, false));
+        TestUtils.assertIdentical(new long[] { 4 }, mListView.getCheckItemIds());
+
+        mInstrumentation.runOnMainSync(() -> mListView.setItemChecked(4, false));
+        assertTrue(mListView.getCheckItemIds().length == 0);
+    }
+
+    public void testAccessOverscrollHeader() {
+        final Drawable overscrollHeaderDrawable = spy(new ColorDrawable(Color.YELLOW));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
+            mListView.setAdapter(mAdapter_longCountries);
+            mListView.setOverscrollHeader(overscrollHeaderDrawable);
+        });
+
+        assertEquals(overscrollHeaderDrawable, mListView.getOverscrollHeader());
+        verify(overscrollHeaderDrawable, never()).draw(any(Canvas.class));
+
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                () -> mListView.setScrollY(-mListView.getHeight() / 2));
+
+        verify(overscrollHeaderDrawable, atLeastOnce()).draw(any(Canvas.class));
+    }
+
+    public void testAccessOverscrollFooter() {
+        final Drawable overscrollFooterDrawable = spy(new ColorDrawable(Color.MAGENTA));
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView, () -> {
+            // Configure ListView to automatically scroll to the selected item
+            mListView.setStackFromBottom(true);
+            mListView.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
+
+            mListView.setAdapter(mAdapter_longCountries);
+            mListView.setOverscrollFooter(overscrollFooterDrawable);
+
+            // Set selection to the last item
+            mListView.setSelection(mAdapter_longCountries.getCount() - 1);
+        });
+
+        assertEquals(overscrollFooterDrawable, mListView.getOverscrollFooter());
+        verify(overscrollFooterDrawable, never()).draw(any(Canvas.class));
+
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+                () -> mListView.setScrollY(mListView.getHeight() / 2));
+
+        verify(overscrollFooterDrawable, atLeastOnce()).draw(any(Canvas.class));
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/MediaControllerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/MediaControllerCtsActivity.java
index ac8f100..ffbc3af 100644
--- a/tests/tests/widget/src/android/widget/cts/MediaControllerCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/MediaControllerCtsActivity.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.MediaController;
-
 import android.widget.cts.R;
 
 /**
diff --git a/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java b/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
index 2c60a91..705f990 100644
--- a/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
@@ -16,10 +16,7 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
 import android.app.Instrumentation;
@@ -31,10 +28,11 @@
 import android.util.Xml;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
+import org.xmlpull.v1.XmlPullParser;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -47,7 +45,6 @@
     private MediaController mMediaController;
     private Activity mActivity;
     private Instrumentation mInstrumentation;
-    private static final long DEFAULT_TIMEOUT = 3000;
 
     public MediaControllerTest() {
         super("android.widget.cts", MediaControllerCtsActivity.class);
@@ -151,12 +148,7 @@
         assertTrue(mMediaController.isShowing());
 
         // isShowing() should return false, but MediaController still shows, this may be a bug.
-        new PollingCheck(timeout + 500) {
-            @Override
-            protected boolean check() {
-                return mMediaController.isShowing();
-            }
-        }.run();
+        PollingCheck.waitFor(500, mMediaController::isShowing);
     }
 
     private String prepareSampleVideo() {
@@ -236,9 +228,9 @@
         mMediaController.setAnchorView(videoView);
         mMediaController.setMediaPlayer(mediaPlayerControl);
 
-        final MockOnClickListener next = new MockOnClickListener();
-        final MockOnClickListener prev = new MockOnClickListener();
-        mMediaController.setPrevNextListeners(next, prev);
+        final View.OnClickListener mockNextClickListener = mock(View.OnClickListener.class);
+        final View.OnClickListener mockPrevClickListener = mock(View.OnClickListener.class);
+        mMediaController.setPrevNextListeners(mockNextClickListener, mockPrevClickListener);
 
         mMediaController.show();
 
@@ -258,9 +250,9 @@
         mMediaController.setAnchorView(videoView);
         mMediaController.setMediaPlayer(mediaPlayerControl);
 
-        final MockOnClickListener next = new MockOnClickListener();
-        final MockOnClickListener prev = new MockOnClickListener();
-        mMediaController.setPrevNextListeners(next, prev);
+        final View.OnClickListener mockNextClickListener = mock(View.OnClickListener.class);
+        final View.OnClickListener mockPrevClickListener = mock(View.OnClickListener.class);
+        mMediaController.setPrevNextListeners(mockNextClickListener, mockPrevClickListener);
     }
 
     private static class MockMediaPlayerControl implements MediaController.MediaPlayerControl {
@@ -318,16 +310,4 @@
             return 0;
         }
     }
-
-    private static class MockOnClickListener implements OnClickListener {
-        private boolean mOnClickCalled = false;
-
-        public boolean hasOnClickCalled() {
-            return mOnClickCalled;
-        }
-
-        public void onClick(View v) {
-            mOnClickCalled = true;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/MockTextView.java b/tests/tests/widget/src/android/widget/cts/MockTextView.java
index 977e4b2..ffdcfde 100644
--- a/tests/tests/widget/src/android/widget/cts/MockTextView.java
+++ b/tests/tests/widget/src/android/widget/cts/MockTextView.java
@@ -16,208 +16,103 @@
 
 package android.widget.cts;
 
+import android.annotation.Nullable;
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Bundle;
 import android.text.method.MovementMethod;
 import android.util.AttributeSet;
-import android.view.ContextMenu;
-import android.view.KeyEvent;
 import android.widget.TextView;
 
 public class MockTextView extends TextView {
-    private boolean mHasCalledOnCreateContextMenu;
-    private boolean mHasCalledOnFocusChanged;
-    private boolean mHasCalledOnMeasure;
-    private boolean mHasCalledOnTextChanged;
-    private boolean mHasCalledDrawableStateChanged;
-    private boolean mHasCalledOnWindowFocusChanged;
-    private boolean mHasCalledOnPrivateIMECommand;
-    private boolean mHasCalledOnKeyMultiple;
 
     public MockTextView(Context context) {
         super(context);
     }
 
-    public MockTextView(Context context, AttributeSet attrs) {
+    public MockTextView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
     }
 
-    public MockTextView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
+    public MockTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
     }
 
-    public boolean hasCalledOnWindowFocusChanged() {
-        return mHasCalledOnWindowFocusChanged;
-    }
-
-    public boolean hasCalledOnCreateContextMenu() {
-        return mHasCalledOnCreateContextMenu;
-    }
-
-    public boolean hasCalledDrawableStateChanged() {
-        return mHasCalledDrawableStateChanged;
-    }
-
-    public boolean hasCalledOnFocusChanged() {
-        return mHasCalledOnFocusChanged;
-    }
-
-    public boolean hasCalledOnMeasure() {
-        return mHasCalledOnMeasure;
-    }
-
-    public boolean hasCalledOnTextChanged() {
-        return mHasCalledOnTextChanged;
-    }
-
-    public boolean hasCalledOnPrivateIMECommand() {
-        return mHasCalledOnPrivateIMECommand;
-    }
-
-    public boolean hasCalledOnKeyMultiple(){
-        return mHasCalledOnKeyMultiple;
-    }
-
-    public void reset() {
-        mHasCalledOnWindowFocusChanged = false;
-        mHasCalledDrawableStateChanged = false;
-        mHasCalledOnCreateContextMenu = false;
-        mHasCalledOnFocusChanged = false;
-        mHasCalledOnMeasure = false;
-        mHasCalledOnTextChanged = false;
-        mHasCalledOnPrivateIMECommand = false;
-        mHasCalledOnKeyMultiple = false;
-    }
-
+    @Override
     public int computeHorizontalScrollRange() {
         return super.computeHorizontalScrollRange();
     }
 
+    @Override
     public int computeVerticalScrollRange() {
         return super.computeVerticalScrollRange();
     }
 
     @Override
-    protected void drawableStateChanged() {
-        super.drawableStateChanged();
-        mHasCalledDrawableStateChanged = true;
-    }
-
     public boolean getDefaultEditable() {
         return super.getDefaultEditable();
     }
 
+    @Override
     public MovementMethod getDefaultMovementMethod() {
         return super.getDefaultMovementMethod();
     }
 
     @Override
-    protected void onCreateContextMenu(ContextMenu menu) {
-        super.onCreateContextMenu(menu);
-        mHasCalledOnCreateContextMenu = true;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-    }
-
-    @Override
-    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
-        super.onFocusChanged(focused, direction, previouslyFocusedRect);
-        mHasCalledOnFocusChanged = true;
-    }
-
-    @Override
-    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
-        mHasCalledOnKeyMultiple = true;
-        return super.onKeyMultiple(keyCode, repeatCount, event);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        mHasCalledOnMeasure = true;
-    }
-
-    @Override
-    protected void onTextChanged(CharSequence text, int start, int before, int after) {
-        super.onTextChanged(text, start, before, after);
-        mHasCalledOnTextChanged = true;
-    }
-
     public boolean setFrame(int l, int t, int r, int b) {
         return super.setFrame(l, t, r, b);
     }
 
     @Override
-    public void onWindowFocusChanged(boolean hasWindowFocus) {
-        super.onWindowFocusChanged(hasWindowFocus);
-        mHasCalledOnWindowFocusChanged = true;
-    }
-
     public float getLeftFadingEdgeStrength() {
         return super.getLeftFadingEdgeStrength();
     }
 
+    @Override
     public float getRightFadingEdgeStrength() {
         return super.getRightFadingEdgeStrength();
     }
 
     @Override
-    public boolean onPrivateIMECommand(String action, Bundle data) {
-        mHasCalledOnPrivateIMECommand = true;
-        return super.onPrivateIMECommand(action, data);
-    }
-
-    public int getFrameLeft() {
-        return getLeft();
-    }
-
-    public int getFrameTop() {
-        return getTop();
-    }
-
-    public int getFrameRight() {
-        return getRight();
-    }
-
-    public int getFrameBottom() {
-        return getBottom();
-    }
-
     public int getBottomPaddingOffset() {
         return super.getBottomPaddingOffset();
     }
 
+    @Override
     public int getLeftPaddingOffset() {
         return super.getLeftPaddingOffset();
     }
 
+    @Override
     public int getRightPaddingOffset() {
         return super.getRightPaddingOffset();
     }
 
+    @Override
     public int getTopPaddingOffset() {
         return super.getTopPaddingOffset();
     }
 
+    @Override
     public boolean isPaddingOffsetRequired() {
         return super.isPaddingOffsetRequired();
     }
 
+    @Override
+    public void onSelectionChanged(int selStart, int selEnd) {
+        super.onSelectionChanged(selStart, selEnd);
+    }
+
+    @Override
+    public void drawableStateChanged() {
+        super.drawableStateChanged();
+    }
+
+    @Override
     public boolean verifyDrawable(Drawable who) {
         return super.verifyDrawable(who);
     }
 
+    @Override
     public int computeVerticalScrollExtent() {
         return super.computeVerticalScrollExtent();
     }
diff --git a/tests/tests/widget/src/android/widget/cts/MockURLSpanTestActivity.java b/tests/tests/widget/src/android/widget/cts/MockURLSpanTestActivity.java
index 3d27f9a..131d2fc 100644
--- a/tests/tests/widget/src/android/widget/cts/MockURLSpanTestActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/MockURLSpanTestActivity.java
@@ -16,8 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
@@ -25,9 +23,19 @@
  * A Mock application for {@link URLSpan} test.
  */
 public class MockURLSpanTestActivity extends Activity {
+    public static final String KEY_PARAM = "MockURLSpanTestActivity.param";
+
+    private String mParam;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        mParam = getIntent().getStringExtra(KEY_PARAM);
         setContentView(R.layout.urlspan_layout);
     }
+
+    public String getParam() {
+        return mParam;
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewCtsActivity.java
index b5de67b..c36ba77 100644
--- a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 /**
  * A minimal application for MultiAutoCompleteTextView test.
diff --git a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java
index 5c18030..fddc9a5 100644
--- a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java
@@ -16,32 +16,35 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Xml;
 import android.view.KeyEvent;
 import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
 import android.widget.Filter;
 import android.widget.MultiAutoCompleteTextView;
 import android.widget.MultiAutoCompleteTextView.CommaTokenizer;
 import android.widget.MultiAutoCompleteTextView.Tokenizer;
 
-public class MultiAutoCompleteTextViewTest extends ActivityInstrumentationTestCase2
-        <MultiAutoCompleteTextViewCtsActivity> {
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+@MediumTest
+public class MultiAutoCompleteTextViewTest
+        extends ActivityInstrumentationTestCase2<MultiAutoCompleteTextViewCtsActivity> {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
     private MultiAutoCompleteTextView mMultiAutoCompleteTextView_country;
     private MultiAutoCompleteTextView mMultiAutoCompleteTextView_name;
-    private Activity mActivity;
 
     public MultiAutoCompleteTextViewTest() {
         super("android.widget.cts", MultiAutoCompleteTextViewCtsActivity.class);
@@ -51,23 +54,26 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        mInstrumentation = getInstrumentation();
         mActivity = getActivity();
-
         mMultiAutoCompleteTextView_country = (MultiAutoCompleteTextView)mActivity
                 .findViewById(R.id.country_edit);
         mMultiAutoCompleteTextView_name = (MultiAutoCompleteTextView)mActivity
                 .findViewById(R.id.name_edit);
     }
 
-    @UiThreadTest
     public void testConstructor() {
-        XmlPullParser parser = mActivity.getResources()
-                .getXml(R.layout.multi_auto_complete_text_view_layout);
-        AttributeSet attr = Xml.asAttributeSet(parser);
-
         new MultiAutoCompleteTextView(mActivity);
-        new MultiAutoCompleteTextView(mActivity, attr);
-        new MultiAutoCompleteTextView(mActivity, attr, 0);
+        new MultiAutoCompleteTextView(mActivity, null);
+        new MultiAutoCompleteTextView(mActivity, null, android.R.attr.autoCompleteTextViewStyle);
+        new MultiAutoCompleteTextView(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_AutoCompleteTextView);
+        new MultiAutoCompleteTextView(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_AutoCompleteTextView);
+        new MultiAutoCompleteTextView(mActivity, null, 0,
+                android.R.style.Widget_Material_AutoCompleteTextView);
+        new MultiAutoCompleteTextView(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_AutoCompleteTextView);
 
         try {
             new MultiAutoCompleteTextView(null);
@@ -91,19 +97,21 @@
         }
     }
 
-    @UiThreadTest
-    private void setText(MultiAutoCompleteTextView m, CharSequence c) {
-        m.setText(c);
-        m.setSelection(0, c.length());
+    private void setText(final MultiAutoCompleteTextView m, final CharSequence c) {
+        mInstrumentation.runOnMainSync(() -> {
+            m.setText(c);
+            m.setSelection(0, c.length());
+        });
     }
 
-    @UiThreadTest
     public void testMultiAutoCompleteTextView() {
-        mMultiAutoCompleteTextView_country.setTokenizer(new CommaTokenizer());
-        mMultiAutoCompleteTextView_name.setTokenizer(new CommaTokenizer());
+        mInstrumentation.runOnMainSync(() -> {
+            mMultiAutoCompleteTextView_country.setTokenizer(new CommaTokenizer());
+            mMultiAutoCompleteTextView_name.setTokenizer(new CommaTokenizer());
 
-        mMultiAutoCompleteTextView_country.setThreshold(3);
-        mMultiAutoCompleteTextView_name.setThreshold(2);
+            mMultiAutoCompleteTextView_country.setThreshold(3);
+            mMultiAutoCompleteTextView_name.setThreshold(2);
+        });
 
         assertFalse(mMultiAutoCompleteTextView_country.enoughToFilter());
         assertFalse(mMultiAutoCompleteTextView_name.enoughToFilter());
@@ -125,76 +133,84 @@
 
         setText(mMultiAutoCompleteTextView_name, "Jacky");
         assertTrue(mMultiAutoCompleteTextView_name.enoughToFilter());
-
-        MockValidator v = new MockValidator();
-        v.setValid(true);
-        mMultiAutoCompleteTextView_name.setValidator(v);
-
-        // There will be an endless loop when using CommaTokenizer as the Tokenizer
-        // mMultiAutoCompleteTextView_name.performValidation();
-        mMultiAutoCompleteTextView_name.setValidator(null);
     }
 
-    @UiThreadTest
     public void testPerformValidation() {
-        MockValidator v = new MockValidator();
-        v.setValid(true);
-        mMultiAutoCompleteTextView_country.setValidator(v);
+        final AutoCompleteTextView.Validator validator = mock(AutoCompleteTextView.Validator.class);
+        when(validator.isValid(any(CharSequence.class))).thenReturn(true);
+        when(validator.fixText(any(CharSequence.class))).thenAnswer(
+                new Answer<CharSequence>() {
+                    @Override
+                    public CharSequence answer(InvocationOnMock invocation) throws Throwable {
+                        // Return the originally passed parameter
+                        return (CharSequence) invocation.getArguments()[0];
+                    }
+                });
+
+        mInstrumentation.runOnMainSync(
+                () -> mMultiAutoCompleteTextView_country.setValidator(validator));
         MockTokenizer t = new MockTokenizer();
-        mMultiAutoCompleteTextView_country.setTokenizer(t);
+        mInstrumentation.runOnMainSync(() -> mMultiAutoCompleteTextView_country.setTokenizer(t));
         String str = new String("Foo, Android Test, OH");
-        mMultiAutoCompleteTextView_country.setText(str);
-        mMultiAutoCompleteTextView_country.performValidation();
+        mInstrumentation.runOnMainSync(() -> {
+            mMultiAutoCompleteTextView_country.setText(str);
+            mMultiAutoCompleteTextView_country.performValidation();
+        });
         assertEquals(str, mMultiAutoCompleteTextView_country.getText().toString());
 
-        v.setValid(false);
-        mMultiAutoCompleteTextView_country.performValidation();
+        when(validator.isValid(any(CharSequence.class))).thenReturn(false);
+        mInstrumentation.runOnMainSync(
+                mMultiAutoCompleteTextView_country::performValidation);
         assertEquals(str + ", ", mMultiAutoCompleteTextView_country.getText().toString());
     }
 
-    @UiThreadTest
     public void testPerformFiltering() {
         MyMultiAutoCompleteTextView multiAutoCompleteTextView =
             new MyMultiAutoCompleteTextView(mActivity);
         CommaTokenizer t = new CommaTokenizer();
-        multiAutoCompleteTextView.setTokenizer(t);
+        mInstrumentation.runOnMainSync(() -> multiAutoCompleteTextView.setTokenizer(t));
 
         ArrayAdapter<String> adapter = new ArrayAdapter<String>(mActivity,
                 R.layout.simple_dropdown_item_1line);
         assertNotNull(adapter);
 
-        multiAutoCompleteTextView.setAdapter(adapter);
+        mInstrumentation.runOnMainSync(() -> multiAutoCompleteTextView.setAdapter(adapter));
         assertNotNull(multiAutoCompleteTextView.getFilter());
 
         String text = "Android test.";
-        multiAutoCompleteTextView.setText(text);
-        multiAutoCompleteTextView.setSelection(0, 12);
+        mInstrumentation.runOnMainSync(() -> {
+            multiAutoCompleteTextView.setText(text);
+            multiAutoCompleteTextView.setSelection(0, 12);
+            multiAutoCompleteTextView.performFiltering(text, KeyEvent.KEYCODE_0);
+        });
 
-        multiAutoCompleteTextView.performFiltering(text, KeyEvent.KEYCODE_0);
         assertNotNull(multiAutoCompleteTextView.getFilter());
 
-        multiAutoCompleteTextView.performFiltering(text, 0, text.length(), KeyEvent.KEYCODE_E);
+        mInstrumentation.runOnMainSync(
+                () -> multiAutoCompleteTextView.performFiltering(text, 0, text.length(),
+                        KeyEvent.KEYCODE_E));
         assertNotNull(multiAutoCompleteTextView.getFilter());
     }
 
-    @UiThreadTest
     public void testReplaceText() {
         MyMultiAutoCompleteTextView multiAutoCompleteTextView =
             new MyMultiAutoCompleteTextView(mActivity);
         CommaTokenizer t = new CommaTokenizer();
-        multiAutoCompleteTextView.setTokenizer(t);
+        mInstrumentation.runOnMainSync(() -> multiAutoCompleteTextView.setTokenizer(t));
 
         String text = "CTS.";
-        multiAutoCompleteTextView.setText(text);
+        mInstrumentation.runOnMainSync(() -> multiAutoCompleteTextView.setText(text));
         assertEquals(text, multiAutoCompleteTextView.getText().toString());
-        multiAutoCompleteTextView.setSelection(0, text.length());
+        mInstrumentation.runOnMainSync(
+                () -> multiAutoCompleteTextView.setSelection(0, text.length()));
 
         // set the selection range.
-        multiAutoCompleteTextView.replaceText("Android Test.");
+        mInstrumentation.runOnMainSync(
+                () -> multiAutoCompleteTextView.replaceText("Android Test."));
         assertEquals("Android Test., ", multiAutoCompleteTextView.getText().toString());
 
         // do not set the selection range.
-        multiAutoCompleteTextView.replaceText("replace test");
+        mInstrumentation.runOnMainSync(() -> multiAutoCompleteTextView.replaceText("replace test"));
         assertEquals("Android Test., replace test, ",
                 multiAutoCompleteTextView.getText().toString());
     }
@@ -253,22 +269,6 @@
         }
     }
 
-    private class MockValidator implements MultiAutoCompleteTextView.Validator {
-        private boolean mIsValid;
-
-        public void setValid(boolean b) {
-            mIsValid = b;
-        }
-
-        public boolean isValid(CharSequence text) {
-            return mIsValid;
-        }
-
-        public CharSequence fixText(CharSequence invalidText) {
-            return invalidText;
-        }
-    }
-
     /**
      * MyMultiAutoCompleteTextView
      */
diff --git a/tests/tests/widget/src/android/widget/cts/MyGallery.java b/tests/tests/widget/src/android/widget/cts/MyGallery.java
index 27b5d45..fc43437 100644
--- a/tests/tests/widget/src/android/widget/cts/MyGallery.java
+++ b/tests/tests/widget/src/android/widget/cts/MyGallery.java
@@ -19,10 +19,9 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.ContextMenu.ContextMenuInfo;
 import android.view.animation.Transformation;
 import android.widget.Gallery;
 
diff --git a/tests/tests/widget/src/android/widget/cts/MyRemotableView.java b/tests/tests/widget/src/android/widget/cts/MyRemotableView.java
new file mode 100644
index 0000000..725ffe7
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/MyRemotableView.java
@@ -0,0 +1,100 @@
+/*
+ * 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.widget.cts;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+@RemoteViews.RemoteView
+public class MyRemotableView extends TextView {
+    private byte mByteField;
+    private char mCharField;
+    private double mDoubleField;
+    private short mShortField;
+    private Bundle mBundleField;
+    private Intent mIntentField;
+
+    public MyRemotableView(Context context) {
+        super(context);
+    }
+
+    public MyRemotableView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public MyRemotableView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @android.view.RemotableViewMethod
+    public void setByteField(byte value) {
+        mByteField = value;
+    }
+
+    public byte getByteField() {
+        return mByteField;
+    }
+
+    @android.view.RemotableViewMethod
+    public void setCharField(char value) {
+        mCharField = value;
+    }
+
+    public char getCharField() {
+        return mCharField;
+    }
+
+    @android.view.RemotableViewMethod
+    public void setDoubleField(double value) {
+        mDoubleField = value;
+    }
+
+    public double getDoubleField() {
+        return mDoubleField;
+    }
+
+    @android.view.RemotableViewMethod
+    public void setShortField(short value) {
+        mShortField = value;
+    }
+
+    public short getShortField() {
+        return mShortField;
+    }
+
+    @android.view.RemotableViewMethod
+    public void setBundleField(Bundle value) {
+        mBundleField = value;
+    }
+
+    public Bundle getBundleField() {
+        return mBundleField;
+    }
+
+    @android.view.RemotableViewMethod
+    public void setIntentField(Intent value) {
+        mIntentField = value;
+    }
+
+    public Intent getIntentField() {
+        return mIntentField;
+    }
+}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/NumberPickerCtsActivity.java
similarity index 67%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/NumberPickerCtsActivity.java
index 481f5be..f93a1da 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.NumberPicker;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link NumberPicker} test.
+ */
+public class NumberPickerCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.numberpicker_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
new file mode 100644
index 0000000..d560f31
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.widget.cts;
+
+import static org.mockito.Mockito.*;
+
+import android.app.Instrumentation;
+import android.cts.util.CtsTouchUtils;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+import android.widget.NumberPicker;
+
+import org.mockito.InOrder;
+
+@SmallTest
+public class NumberPickerTest extends ActivityInstrumentationTestCase2<NumberPickerCtsActivity> {
+    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 Instrumentation mInstrumentation;
+    private NumberPickerCtsActivity mActivity;
+    private NumberPicker mNumberPicker;
+
+    public NumberPickerTest() {
+        super("android.widget.cts", NumberPickerCtsActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+        mNumberPicker = (NumberPicker) mActivity.findViewById(R.id.number_picker);
+    }
+
+    @UiThreadTest
+    public void testConstructor() {
+        new NumberPicker(mActivity);
+
+        new NumberPicker(mActivity, null);
+
+        new NumberPicker(mActivity, null, android.R.attr.numberPickerStyle);
+
+        new NumberPicker(mActivity, null, 0, android.R.style.Widget_Material_NumberPicker);
+
+        new NumberPicker(mActivity, null, 0, android.R.style.Widget_Material_Light_NumberPicker);
+    }
+
+    private void verifyDisplayedValues(String[] expected) {
+        final String[] displayedValues = mNumberPicker.getDisplayedValues();
+        assertEquals(expected.length, displayedValues.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals(expected[i], displayedValues[i]);
+        }
+    }
+
+    public void testSetDisplayedValuesRangeMatch() {
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(10);
+            mNumberPicker.setMaxValue(12);
+            mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+        });
+
+        assertEquals(10, mNumberPicker.getMinValue());
+        assertEquals(12, mNumberPicker.getMaxValue());
+        verifyDisplayedValues(NUMBER_NAMES3);
+
+        // Set a different displayed values array, but still matching the min/max range
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+        });
+
+        assertEquals(10, mNumberPicker.getMinValue());
+        assertEquals(12, mNumberPicker.getMaxValue());
+        verifyDisplayedValues(NUMBER_NAMES_ALT3);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(24);
+            mNumberPicker.setMaxValue(26);
+        });
+
+        assertEquals(24, mNumberPicker.getMinValue());
+        assertEquals(26, mNumberPicker.getMaxValue());
+        verifyDisplayedValues(NUMBER_NAMES_ALT3);
+    }
+
+    public void testSetDisplayedValuesRangeMismatch() {
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(10);
+            mNumberPicker.setMaxValue(14);
+        });
+        assertEquals(10, mNumberPicker.getMinValue());
+        assertEquals(14, mNumberPicker.getMaxValue());
+
+        // Try setting too few displayed entries
+        mInstrumentation.runOnMainSync(() -> {
+            try {
+                // This is expected to fail since the displayed values only has three entries,
+                // while the min/max range has five.
+                mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+                fail("The size of the displayed values array must be equal to min/max range!");
+            } catch (Exception e) {
+                // We are expecting to catch an exception. Set displayed values to an array that
+                // matches the min/max range.
+                mNumberPicker.setDisplayedValues(NUMBER_NAMES5);
+            }
+        });
+    }
+
+    public void testSelectionDisplayedValueFromDisplayedValues() {
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(1);
+            mNumberPicker.setMaxValue(3);
+            mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+        });
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[0],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[1],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(3));
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[2],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        // Switch to a different displayed values array
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+        });
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[2],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[0],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[1],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+    }
+
+    public void testSelectionDisplayedValueFromFormatter() {
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(0);
+            mNumberPicker.setMaxValue(4);
+            mNumberPicker.setFormatter((int value) -> "entry " + value);
+        });
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(0));
+        assertTrue(TextUtils.equals("entry 0",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+        assertTrue(TextUtils.equals("entry 1",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+        assertTrue(TextUtils.equals("entry 2",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(3));
+        assertTrue(TextUtils.equals("entry 3",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(4));
+        assertTrue(TextUtils.equals("entry 4",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        // Switch to a different formatter
+        mInstrumentation.runOnMainSync(
+                () -> mNumberPicker.setFormatter((int value) -> "row " + value));
+        // Check that the currently selected value has new displayed value
+        assertTrue(TextUtils.equals("row 4",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        // and check a couple more values for the new formatting
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(0));
+        assertTrue(TextUtils.equals("row 0",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+        assertTrue(TextUtils.equals("row 1",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+    }
+
+
+    public void testSelectionDisplayedValuePrecedence() {
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(1);
+            mNumberPicker.setMaxValue(3);
+            mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+            mNumberPicker.setFormatter((int value) -> "entry " + value);
+        });
+
+        // According to the widget documentation, displayed values take precedence over formatter
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[0],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[1],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(3));
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[2],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        // Set displayed values to null and test that the widget is using the formatter
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setDisplayedValues(null));
+        assertTrue(TextUtils.equals("entry 3",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+        assertTrue(TextUtils.equals("entry 1",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+        assertTrue(TextUtils.equals("entry 2",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        // Set a different displayed values array and test that it's taking precedence
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3));
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[1],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[0],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(3));
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[2],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+    }
+
+    public void testAccessValue() {
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(20);
+            mNumberPicker.setMaxValue(22);
+            mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+        });
+
+        final NumberPicker.OnValueChangeListener mockValueChangeListener =
+                mock(NumberPicker.OnValueChangeListener.class);
+        mNumberPicker.setOnValueChangedListener(mockValueChangeListener);
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(21));
+        assertEquals(21, mNumberPicker.getValue());
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(20));
+        assertEquals(20, mNumberPicker.getValue());
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(22));
+        assertEquals(22, mNumberPicker.getValue());
+
+        // Check trying to set value out of min/max range
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(10));
+        assertEquals(20, mNumberPicker.getValue());
+
+        mInstrumentation.runOnMainSync(() -> 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.
+        verifyZeroInteractions(mockValueChangeListener);
+    }
+
+    public void testInteractionWithSwipeDown() {
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(6);
+            mNumberPicker.setMaxValue(8);
+            mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+        });
+
+        final NumberPicker.OnValueChangeListener mockValueChangeListener =
+                mock(NumberPicker.OnValueChangeListener.class);
+        mNumberPicker.setOnValueChangedListener(mockValueChangeListener);
+
+        final NumberPicker.OnScrollListener mockScrollListener =
+                mock(NumberPicker.OnScrollListener.class);
+        mNumberPicker.setOnScrollListener(mockScrollListener);
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(7));
+        assertEquals(7, mNumberPicker.getValue());
+
+        // Swipe down across our number picker
+        final int[] numberPickerLocationOnScreen = new int[2];
+        mNumberPicker.getLocationOnScreen(numberPickerLocationOnScreen);
+
+        CtsTouchUtils.emulateDragGesture(mInstrumentation,
+                numberPickerLocationOnScreen[0] + mNumberPicker.getWidth() / 2,
+                numberPickerLocationOnScreen[1] + 1,
+                0,
+                mNumberPicker.getHeight() - 2);
+
+        // At this point we expect that the drag-down gesture has selected the value
+        // that was "above" the previously selected one, and that our value change listener
+        // has been notified of that change exactly once.
+        assertEquals(6, mNumberPicker.getValue());
+        verify(mockValueChangeListener, times(1)).onValueChange(mNumberPicker, 7, 6);
+        verifyNoMoreInteractions(mockValueChangeListener);
+
+        // We expect that our scroll listener will be called with specific state changes.
+        InOrder inOrder = inOrder(mockScrollListener);
+        inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+                NumberPicker.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
+        inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+                NumberPicker.OnScrollListener.SCROLL_STATE_IDLE);
+        verifyNoMoreInteractions(mockScrollListener);
+    }
+
+    public void testInteractionWithSwipeUp() {
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(10);
+            mNumberPicker.setMaxValue(12);
+            mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+        });
+
+        final NumberPicker.OnValueChangeListener mockValueChangeListener =
+                mock(NumberPicker.OnValueChangeListener.class);
+        mNumberPicker.setOnValueChangedListener(mockValueChangeListener);
+
+        final NumberPicker.OnScrollListener mockScrollListener =
+                mock(NumberPicker.OnScrollListener.class);
+        mNumberPicker.setOnScrollListener(mockScrollListener);
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(11));
+        assertEquals(11, mNumberPicker.getValue());
+
+        // Swipe up across our number picker
+        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));
+
+        // 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
+        // has been notified of that change exactly once.
+        assertEquals(12, mNumberPicker.getValue());
+        verify(mockValueChangeListener, times(1)).onValueChange(mNumberPicker, 11, 12);
+        verifyNoMoreInteractions(mockValueChangeListener);
+
+        // We expect that our scroll listener will be called with specific state changes.
+        InOrder inOrder = inOrder(mockScrollListener);
+        inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+                NumberPicker.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
+        inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+                NumberPicker.OnScrollListener.SCROLL_STATE_IDLE);
+        verifyNoMoreInteractions(mockScrollListener);
+    }
+
+    public void testAccessWrapSelectorValue() {
+        mInstrumentation.runOnMainSync(() -> {
+            mNumberPicker.setMinValue(100);
+            mNumberPicker.setMaxValue(200);
+        });
+        // As specified in the Javadocs of NumberPicker.setWrapSelectorWheel, when min/max
+        // range is larger than what the widget is showing, the selector wheel is enabled.
+        assertTrue(mNumberPicker.getWrapSelectorWheel());
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setWrapSelectorWheel(false));
+        assertFalse(mNumberPicker.getWrapSelectorWheel());
+
+        mInstrumentation.runOnMainSync(() -> mNumberPicker.setWrapSelectorWheel(true));
+        assertTrue(mNumberPicker.getWrapSelectorWheel());
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index ee38448..99287b0 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -16,23 +16,22 @@
 
 package android.widget.cts;
 
+import static org.mockito.Mockito.*;
+
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.os.SystemClock;
+import android.cts.util.CtsTouchUtils;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.Gravity;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
-import android.view.MotionEvent;
 import android.view.SubMenu;
 import android.view.View;
 import android.widget.EditText;
 import android.widget.PopupMenu;
 
-import static org.mockito.Mockito.*;
-
 @SmallTest
 public class PopupMenuTest extends
         ActivityInstrumentationTestCase2<PopupMenuCtsActivity> {
@@ -70,7 +69,7 @@
     protected void tearDown() throws Exception {
         if (mPopupMenu != null) {
             try {
-                runTestOnUiThread(() -> mPopupMenu.dismiss());
+                runTestOnUiThread(mPopupMenu::dismiss);
             } catch (Throwable t) {
                 throw new RuntimeException(t);
             }
@@ -97,7 +96,7 @@
 
     public void testPopulateViaInflater() throws Throwable {
         mBuilder = new Builder().inflateWithInflater(true);
-        runTestOnUiThread(() -> mBuilder.show());
+        runTestOnUiThread(mBuilder::show);
         mInstrumentation.waitForIdleSync();
 
         verifyMenuContent();
@@ -105,7 +104,7 @@
 
     public void testDirectPopulate() throws Throwable {
         mBuilder = new Builder().inflateWithInflater(false);
-        runTestOnUiThread(() -> mBuilder.show());
+        runTestOnUiThread(mBuilder::show);
         mInstrumentation.waitForIdleSync();
 
         verifyMenuContent();
@@ -113,7 +112,7 @@
 
     public void testAccessGravity() throws Throwable {
         mBuilder = new Builder();
-        runTestOnUiThread(() -> mBuilder.show());
+        runTestOnUiThread(mBuilder::show);
 
         assertEquals(Gravity.NO_GRAVITY, mPopupMenu.getGravity());
         mPopupMenu.setGravity(Gravity.TOP);
@@ -122,23 +121,23 @@
 
     public void testConstructorWithGravity() throws Throwable {
         mBuilder = new Builder().withGravity(Gravity.TOP);
-        runTestOnUiThread(() -> mBuilder.show());
+        runTestOnUiThread(mBuilder::show);
 
         assertEquals(Gravity.TOP, mPopupMenu.getGravity());
     }
 
     public void testDismissalViaAPI() throws Throwable {
         mBuilder = new Builder().withDismissListener();
-        runTestOnUiThread(() -> mBuilder.show());
+        runTestOnUiThread(mBuilder::show);
 
         mInstrumentation.waitForIdleSync();
         verify(mBuilder.mOnDismissListener, never()).onDismiss(mPopupMenu);
 
-        runTestOnUiThread(() -> mPopupMenu.dismiss());
+        runTestOnUiThread(mPopupMenu::dismiss);
         mInstrumentation.waitForIdleSync();
         verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
 
-        runTestOnUiThread(() -> mPopupMenu.dismiss());
+        runTestOnUiThread(mPopupMenu::dismiss);
         mInstrumentation.waitForIdleSync();
         // Shouldn't have any more interactions with our dismiss listener since the menu was
         // already dismissed when we called dismiss()
@@ -151,7 +150,7 @@
         // "click" a submenu item.
         mBuilder = new Builder().withDismissListener()
                 .withPopupStyleResource(R.style.PopupWindow_NullTransitions);
-        runTestOnUiThread(() -> mBuilder.show());
+        runTestOnUiThread(mBuilder::show);
         mInstrumentation.waitForIdleSync();
         verify(mBuilder.mOnDismissListener, never()).onDismiss(mPopupMenu);
 
@@ -162,11 +161,11 @@
                         performIdentifierAction(R.id.action_share_email, 0));
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(() -> mPopupMenu.dismiss());
+        runTestOnUiThread(mPopupMenu::dismiss);
         mInstrumentation.waitForIdleSync();
         verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
 
-        runTestOnUiThread(() -> mPopupMenu.dismiss());
+        runTestOnUiThread(mPopupMenu::dismiss);
         mInstrumentation.waitForIdleSync();
         // Shouldn't have any more interactions with our dismiss listener since the menu was
         // already dismissed when we called dismiss()
@@ -180,47 +179,18 @@
         mBuilder = new Builder().withDismissListener()
                 .withPopupMenuContent(R.menu.popup_menu_single)
                 .withPopupStyleResource(R.style.PopupWindow_NullTransitions);
-        runTestOnUiThread(() -> mBuilder.show());
+        runTestOnUiThread(mBuilder::show);
         mInstrumentation.waitForIdleSync();
 
-        // Determine the location of the anchor on the screen so that we can emulate
-        // a tap outside of the popup bounds to dismiss the popup
-        final int[] anchorOnScreenXY = new int[2];
-        mBuilder.mAnchor.getLocationOnScreen(anchorOnScreenXY);
-
-        int emulatedTapX = anchorOnScreenXY[0] + 10;
-        int emulatedTapY = anchorOnScreenXY[1] - 20;
-
-        // The logic below uses Instrumentation to emulate a tap outside the bounds of the
+        // The call below uses Instrumentation to emulate a tap outside the bounds of the
         // displayed popup menu. This tap is then treated by the framework to be "split" as
         // the ACTION_OUTSIDE for the popup itself, as well as DOWN / MOVE / UP for the underlying
         // view root if the popup is not modal.
         // It is not correct to emulate these two sequences separately in the test, as it
-        // wouldn't emulate the user-facing interaction for this test. Note that usage
-        // of Instrumentation is necessary here since Espresso's actions operate at the level
-        // of view or data. Also, we don't want to use View.dispatchTouchEvent directly as
-        // that would require emulation of two separate sequences as well.
-
-        // Inject DOWN event
-        long downTime = SystemClock.uptimeMillis();
-        MotionEvent eventDown = MotionEvent.obtain(
-                downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
-        mInstrumentation.sendPointerSync(eventDown);
-
-        // Inject MOVE event
-        long moveTime = SystemClock.uptimeMillis();
-        MotionEvent eventMove = MotionEvent.obtain(
-                moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedTapX, emulatedTapY, 1);
-        mInstrumentation.sendPointerSync(eventMove);
-
-        // Inject UP event
-        long upTime = SystemClock.uptimeMillis();
-        MotionEvent eventUp = MotionEvent.obtain(
-                upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
-        mInstrumentation.sendPointerSync(eventUp);
-
-        // Wait for the system to process all events in the queue
-        mInstrumentation.waitForIdleSync();
+        // wouldn't emulate the user-facing interaction for this test. Also, we don't want to use
+        // View.dispatchTouchEvent directly as that would require emulation of two separate
+        // sequences as well.
+        CtsTouchUtils.emulateTapOnScreen(mInstrumentation, mBuilder.mAnchor, 10, -20);
 
         // At this point our popup should have notified its dismiss listener
         verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
@@ -228,7 +198,7 @@
 
     public void testSimpleMenuItemClickViaAPI() throws Throwable {
         mBuilder = new Builder().withMenuItemClickListener().withDismissListener();
-        runTestOnUiThread(() -> mBuilder.show());
+        runTestOnUiThread(mBuilder::show);
 
         // Verify that our menu item click listener hasn't been called yet
         verify(mBuilder.mOnMenuItemClickListener, never()).onMenuItemClick(any(MenuItem.class));
@@ -251,7 +221,7 @@
         // "click" a submenu item.
         mBuilder = new Builder().withDismissListener().withMenuItemClickListener()
                 .withPopupStyleResource(R.style.PopupWindow_NullTransitions);
-        runTestOnUiThread(() -> mBuilder.show());
+        runTestOnUiThread(mBuilder::show);
         mInstrumentation.waitForIdleSync();
 
         // Verify that our menu item click listener hasn't been called yet
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 47efffc..97d6e62 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -16,16 +16,20 @@
 
 package android.widget.cts;
 
+import static org.mockito.Mockito.*;
+
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.graphics.Color;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.transition.Transition;
 import android.transition.Transition.TransitionListener;
 import android.transition.TransitionValues;
@@ -44,13 +48,7 @@
 import android.widget.TextView;
 import android.widget.cts.R;
 
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
+@SmallTest
 public class PopupWindowTest extends
         ActivityInstrumentationTestCase2<PopupWindowCtsActivity> {
     private Instrumentation mInstrumentation;
@@ -84,6 +82,14 @@
 
         new PopupWindow(mActivity, null, android.R.attr.popupWindowStyle);
 
+        new PopupWindow(mActivity, null, 0, android.R.style.Widget_DeviceDefault_PopupWindow);
+
+        new PopupWindow(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Light_PopupWindow);
+
+        new PopupWindow(mActivity, null, 0, android.R.style.Widget_Material_PopupWindow);
+
+        new PopupWindow(mActivity, null, 0, android.R.style.Widget_Material_Light_PopupWindow);
+
         mPopupWindow = new PopupWindow();
         assertEquals(0, mPopupWindow.getWidth());
         assertEquals(0, mPopupWindow.getHeight());
@@ -509,7 +515,7 @@
         assertTrue("Content (" + contentFrame + ") extends outside display (" + displayFrame + ")",
                 displayFrame.contains(contentFrame));
 
-        getInstrumentation().runOnMainSync(() -> popup.dismiss());
+        getInstrumentation().runOnMainSync(popup::dismiss);
         getInstrumentation().waitForIdleSync();
 
         assertFalse(popup.isShowing());
@@ -576,6 +582,8 @@
         // Do not attach within the decor; we will be measuring location
         // with regard to screen coordinates.
         mPopupWindow.setAttachedInDecor(false);
+        assertFalse(mPopupWindow.isAttachedInDecor());
+
         final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
 
         final int xOff = 10;
@@ -661,42 +669,73 @@
 
     public void testGetMaxAvailableHeight() {
         mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+        final Point point = new Point();
+        getDisplay().getSize(point);
+        final int displayHeight = point.y;
 
         View anchorView = mActivity.findViewById(R.id.anchor_upper);
-        int avaliable = getDisplay().getHeight() - anchorView.getHeight();
+        int available = displayHeight - anchorView.getHeight();
         int maxAvailableHeight = mPopupWindow.getMaxAvailableHeight(anchorView);
+        int maxAvailableHeightIgnoringBottomDecoration =
+                mPopupWindow.getMaxAvailableHeight(anchorView, 0, true);
         assertTrue(maxAvailableHeight > 0);
-        assertTrue(maxAvailableHeight <= avaliable);
+        assertTrue(maxAvailableHeight <= available);
+        assertTrue(maxAvailableHeightIgnoringBottomDecoration >= maxAvailableHeight);
+        assertTrue(maxAvailableHeightIgnoringBottomDecoration <= available);
+
         int maxAvailableHeightWithOffset = mPopupWindow.getMaxAvailableHeight(anchorView, 2);
         assertEquals(maxAvailableHeight - 2, maxAvailableHeightWithOffset);
+
         maxAvailableHeightWithOffset =
                 mPopupWindow.getMaxAvailableHeight(anchorView, maxAvailableHeight);
         assertTrue(maxAvailableHeightWithOffset > 0);
-        assertTrue(maxAvailableHeightWithOffset <= avaliable);
+        assertTrue(maxAvailableHeightWithOffset <= available);
+
         maxAvailableHeightWithOffset =
                 mPopupWindow.getMaxAvailableHeight(anchorView, maxAvailableHeight / 2 - 1);
         assertTrue(maxAvailableHeightWithOffset > 0);
-        assertTrue(maxAvailableHeightWithOffset <= avaliable);
+        assertTrue(maxAvailableHeightWithOffset <= available);
+
         maxAvailableHeightWithOffset = mPopupWindow.getMaxAvailableHeight(anchorView, -1);
         assertTrue(maxAvailableHeightWithOffset > 0);
-        assertTrue(maxAvailableHeightWithOffset <= avaliable);
+        assertTrue(maxAvailableHeightWithOffset <= available);
+
+        int maxAvailableHeightWithOffsetIgnoringBottomDecoration =
+                mPopupWindow.getMaxAvailableHeight(anchorView, 2, true);
+        assertEquals(maxAvailableHeightIgnoringBottomDecoration - 2,
+                maxAvailableHeightWithOffsetIgnoringBottomDecoration);
+
+        maxAvailableHeightWithOffsetIgnoringBottomDecoration =
+                mPopupWindow.getMaxAvailableHeight(anchorView, maxAvailableHeight, true);
+        assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration > 0);
+        assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration <= available);
+
+        maxAvailableHeightWithOffsetIgnoringBottomDecoration =
+                mPopupWindow.getMaxAvailableHeight(anchorView, maxAvailableHeight / 2 - 1, true);
+        assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration > 0);
+        assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration <= available);
+
+        maxAvailableHeightWithOffsetIgnoringBottomDecoration =
+                mPopupWindow.getMaxAvailableHeight(anchorView, -1, true);
+        assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration > 0);
+        assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration <= available);
 
         anchorView = mActivity.findViewById(R.id.anchor_lower);
         // On some devices the view might actually have larger size than the physical display
         // due to chin and content will be laid out as if outside of the display. We need to use
         // larger from the display height and the main view height.
-        avaliable = Math.max(getDisplay().getHeight(),
+        available = Math.max(displayHeight,
                 mActivity.findViewById(android.R.id.content).getHeight()) - anchorView.getHeight();
         maxAvailableHeight = mPopupWindow.getMaxAvailableHeight(anchorView);
         assertTrue(maxAvailableHeight > 0);
-        assertTrue(maxAvailableHeight <= avaliable);
+        assertTrue(maxAvailableHeight <= available);
 
         anchorView = mActivity.findViewById(R.id.anchor_middle_left);
-        avaliable = getDisplay().getHeight() - anchorView.getHeight()
+        available = displayHeight - anchorView.getHeight()
                 - mActivity.findViewById(R.id.anchor_upper).getHeight();
         maxAvailableHeight = mPopupWindow.getMaxAvailableHeight(anchorView);
         assertTrue(maxAvailableHeight > 0);
-        assertTrue(maxAvailableHeight <= avaliable);
+        assertTrue(maxAvailableHeight <= available);
     }
 
     @UiThreadTest
@@ -756,7 +795,7 @@
         assertEquals(0, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS & p.flags);
         assertEquals(0, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM & p.flags);
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.update());
+        mInstrumentation.runOnMainSync(mPopupWindow::update);
         mInstrumentation.waitForIdleSync();
 
         assertEquals(WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES,
@@ -798,7 +837,7 @@
         verify(exitListener, never()).onTransitionStart(any(Transition.class));
         verify(dismissListener, never()).onDismiss();
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.dismiss());
+        mInstrumentation.runOnMainSync(mPopupWindow::dismiss);
         mInstrumentation.waitForIdleSync();
         verify(enterListener, times(1)).onTransitionStart(any(Transition.class));
         verify(exitListener, times(1)).onTransitionStart(any(Transition.class));
@@ -821,6 +860,7 @@
         mInstrumentation.waitForIdleSync();
         // Do not update if it is not shown
         assertFalse(mPopupWindow.isShowing());
+        assertFalse(mPopupWindow.isAttachedInDecor());
         assertEquals(100, mPopupWindow.getWidth());
         assertEquals(100, mPopupWindow.getHeight());
 
@@ -830,6 +870,14 @@
         containerView.getWindowDisplayFrame(containingRect);
 
         // update if it is not shown
+        mInstrumentation.runOnMainSync(() -> mPopupWindow.update(80, 80));
+
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mPopupWindow.isShowing());
+        assertEquals(80, mPopupWindow.getWidth());
+        assertEquals(80, mPopupWindow.getHeight());
+
+        // update if it is not shown
         mInstrumentation.runOnMainSync(() -> mPopupWindow.update(20, 50, 50, 50));
 
         mInstrumentation.waitForIdleSync();
@@ -884,7 +932,7 @@
         assertEquals(50, mPopupWindow.getWidth());
         assertEquals(50, mPopupWindow.getHeight());
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.dismiss());
+        mInstrumentation.runOnMainSync(mPopupWindow::dismiss);
         mInstrumentation.waitForIdleSync();
     }
 
@@ -1069,6 +1117,61 @@
         assertEquals(LayoutParams.MATCH_PARENT, p.height);
     }
 
+    public void testAccessElevation() {
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+        mInstrumentation.runOnMainSync(() -> mPopupWindow.setElevation(2.0f));
+
+        showPopup();
+        assertEquals(2.0f, mPopupWindow.getElevation());
+
+        dismissPopup();
+        mInstrumentation.runOnMainSync(() -> mPopupWindow.setElevation(4.0f));
+        showPopup();
+        assertEquals(4.0f, mPopupWindow.getElevation());
+
+        dismissPopup();
+        mInstrumentation.runOnMainSync(() -> mPopupWindow.setElevation(10.0f));
+        showPopup();
+        assertEquals(10.0f, mPopupWindow.getElevation());
+    }
+
+    public void testAccessSoftInputMode() {
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+        mInstrumentation.runOnMainSync(
+                () -> mPopupWindow.setSoftInputMode(
+                        WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE));
+
+        showPopup();
+        assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE,
+                mPopupWindow.getSoftInputMode());
+
+        dismissPopup();
+        mInstrumentation.runOnMainSync(
+                () -> mPopupWindow.setSoftInputMode(
+                        WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN));
+        showPopup();
+        assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN,
+                mPopupWindow.getSoftInputMode());
+    }
+
+    public void testAccessSplitTouchEnabled() {
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+        mInstrumentation.runOnMainSync(() -> mPopupWindow.setSplitTouchEnabled(true));
+
+        showPopup();
+        assertTrue(mPopupWindow.isSplitTouchEnabled());
+
+        dismissPopup();
+        mInstrumentation.runOnMainSync(() -> mPopupWindow.setSplitTouchEnabled(false));
+        showPopup();
+        assertFalse(mPopupWindow.isSplitTouchEnabled());
+
+        dismissPopup();
+        mInstrumentation.runOnMainSync(() -> mPopupWindow.setSplitTouchEnabled(true));
+        showPopup();
+        assertTrue(mPopupWindow.isSplitTouchEnabled());
+    }
+
     private static class BaseTransition extends Transition {
         @Override
         public void captureStartValues(TransitionValues transitionValues) {}
diff --git a/tests/tests/widget/src/android/widget/cts/PositionTesterContextMenuListener.java b/tests/tests/widget/src/android/widget/cts/PositionTesterContextMenuListener.java
index a1c9bc4..5d9fd4c 100644
--- a/tests/tests/widget/src/android/widget/cts/PositionTesterContextMenuListener.java
+++ b/tests/tests/widget/src/android/widget/cts/PositionTesterContextMenuListener.java
@@ -17,11 +17,11 @@
 package android.widget.cts;
 
 import android.view.ContextMenu;
-import android.view.View;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View;
 import android.view.View.OnCreateContextMenuListener;
-import android.widget.ExpandableListView;
 import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.ExpandableListView;
 
 public class PositionTesterContextMenuListener implements OnCreateContextMenuListener {
 
diff --git a/tests/tests/widget/src/android/widget/cts/ProgressBarCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ProgressBarCtsActivity.java
index 8298d5f..2b3a45d 100644
--- a/tests/tests/widget/src/android/widget/cts/ProgressBarCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarCtsActivity.java
@@ -18,17 +18,18 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.ProgressBar;
 
 /**
- * An application for ProgressBar test
- *
+ * A minimal application for {@link ProgressBar} test.
  */
 public class ProgressBarCtsActivity extends Activity {
     /**
-     * Called with the activity is first created.
+     * Called when the activity is first created.
      */
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.progressbar_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
index 1cf7334..b2272d2 100644
--- a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
@@ -16,412 +16,449 @@
 
 package android.widget.cts;
 
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.view.LayoutInflater;
-
-import android.widget.cts.R;
-
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.graphics.Canvas;
-import android.graphics.ColorFilter;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
-import android.test.InstrumentationTestCase;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.view.View;
 import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.widget.ProgressBar;
+import android.widget.cts.util.TestUtils;
 
-public class ProgressBarTest extends InstrumentationTestCase {
-    // The target context.
-    private Context mContext;
+@SmallTest
+public class ProgressBarTest extends ActivityInstrumentationTestCase2<ProgressBarCtsActivity> {
+    private ProgressBarCtsActivity mActivity;
+    private ProgressBar mProgressBar;
+    private ProgressBar mProgressBarHorizontal;
+
+    public ProgressBarTest() {
+        super("android.widget.cts", ProgressBarCtsActivity.class);
+    }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+
+        mActivity = getActivity();
+        mProgressBar = (ProgressBar) mActivity.findViewById(R.id.progress);
+        mProgressBarHorizontal = (ProgressBar) mActivity.findViewById(R.id.progress_horizontal);
     }
 
     public void testConstructor() {
-        new ProgressBar(mContext);
+        new ProgressBar(mActivity);
 
-        new ProgressBar(mContext, null);
+        new ProgressBar(mActivity, null);
 
-        new ProgressBar(mContext, null, android.R.attr.progressBarStyle);
+        new ProgressBar(mActivity, null, android.R.attr.progressBarStyle);
+
+        new ProgressBar(mActivity, null, android.R.attr.progressBarStyleHorizontal);
+
+        new ProgressBar(mActivity, null, android.R.attr.progressBarStyleInverse);
+
+        new ProgressBar(mActivity, null, android.R.attr.progressBarStyleLarge);
+
+        new ProgressBar(mActivity, null, android.R.attr.progressBarStyleLargeInverse);
+
+        new ProgressBar(mActivity, null, android.R.attr.progressBarStyleSmall);
+
+        new ProgressBar(mActivity, null, android.R.attr.progressBarStyleSmallInverse);
+
+        new ProgressBar(mActivity, null, android.R.attr.progressBarStyleSmallTitle);
+
+        new ProgressBar(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Light_ProgressBar);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_ProgressBar_Horizontal);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_ProgressBar_Inverse);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_ProgressBar_Large);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_ProgressBar_Large_Inverse);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_ProgressBar_Small);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_ProgressBar_Small_Inverse);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_ProgressBar_Small_Title);
+
+        new ProgressBar(mActivity, null, 0, android.R.style.Widget_Material_Light_ProgressBar);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_ProgressBar_Horizontal);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_ProgressBar_Inverse);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_ProgressBar_Large);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_ProgressBar_Large_Inverse);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_ProgressBar_Small);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_ProgressBar_Small_Inverse);
+
+        new ProgressBar(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_ProgressBar_Small_Title);
     }
 
+    @UiThreadTest
     public void testSetIndeterminate() {
-        ProgressBar progressBar = new ProgressBar(mContext);
-        assertTrue(progressBar.isIndeterminate());
+        assertTrue(mProgressBar.isIndeterminate());
 
-        progressBar.setIndeterminate(true);
-        assertTrue(progressBar.isIndeterminate());
+        mProgressBar.setIndeterminate(true);
+        assertTrue(mProgressBar.isIndeterminate());
 
-        progressBar.setIndeterminate(false);
+        mProgressBar.setIndeterminate(false);
         // because default is Indeterminate only progressBar, can't change the status
-        assertTrue(progressBar.isIndeterminate());
+        assertTrue(mProgressBar.isIndeterminate());
 
-        progressBar = new ProgressBar(mContext, null, android.R.attr.progressBarStyleHorizontal);
-        assertFalse(progressBar.isIndeterminate());
+        assertFalse(mProgressBarHorizontal.isIndeterminate());
 
-        progressBar.setIndeterminate(true);
-        assertTrue(progressBar.isIndeterminate());
+        mProgressBarHorizontal.setIndeterminate(true);
+        assertTrue(mProgressBarHorizontal.isIndeterminate());
 
-        progressBar.setIndeterminate(false);
-        assertFalse(progressBar.isIndeterminate());
+        mProgressBarHorizontal.setIndeterminate(false);
+        assertFalse(mProgressBarHorizontal.isIndeterminate());
     }
 
+    @UiThreadTest
     public void testAccessIndeterminateDrawable() {
-        ProgressBar progressBar = new ProgressBar(mContext);
-
         // set IndeterminateDrawable
         // normal value
-        MockDrawable mockDrawable = new MockDrawable();
-        progressBar.setIndeterminateDrawable(mockDrawable);
-        assertSame(mockDrawable, progressBar.getIndeterminateDrawable());
-        assertFalse(mockDrawable.hasCalledDraw());
-        progressBar.draw(new Canvas());
-        assertTrue(mockDrawable.hasCalledDraw());
+        Drawable mockProgressDrawable = spy(new ColorDrawable(Color.YELLOW));
+        mProgressBar.setIndeterminateDrawable(mockProgressDrawable);
+        assertSame(mockProgressDrawable, mProgressBar.getIndeterminateDrawable());
+        verify(mockProgressDrawable, never()).draw(any(Canvas.class));
+        mProgressBar.draw(new Canvas());
+        verify(mockProgressDrawable, atLeastOnce()).draw(any(Canvas.class));
 
         // exceptional value
-        progressBar.setIndeterminateDrawable(null);
-        assertNull(progressBar.getIndeterminateDrawable());
+        mProgressBar.setIndeterminateDrawable(null);
+        assertNull(mProgressBar.getIndeterminateDrawable());
     }
 
+    @UiThreadTest
     public void testAccessProgressDrawable() {
-        ProgressBar progressBar = new ProgressBar(mContext, null,
-                android.R.attr.progressBarStyleHorizontal);
-
         // set ProgressDrawable
         // normal value
-        MockDrawable mockDrawable = new MockDrawable();
-        progressBar.setProgressDrawable(mockDrawable);
-        assertSame(mockDrawable, progressBar.getProgressDrawable());
-        assertFalse(mockDrawable.hasCalledDraw());
-        progressBar.draw(new Canvas());
-        assertTrue(mockDrawable.hasCalledDraw());
+        Drawable mockProgressDrawable = spy(new ColorDrawable(Color.BLUE));
+        mProgressBarHorizontal.setProgressDrawable(mockProgressDrawable);
+        assertSame(mockProgressDrawable, mProgressBarHorizontal.getProgressDrawable());
+        verify(mockProgressDrawable, never()).draw(any(Canvas.class));
+        mProgressBarHorizontal.draw(new Canvas());
+        verify(mockProgressDrawable, atLeastOnce()).draw(any(Canvas.class));
 
         // exceptional value
-        progressBar.setProgressDrawable(null);
-        assertNull(progressBar.getProgressDrawable());
+        mProgressBarHorizontal.setProgressDrawable(null);
+        assertNull(mProgressBarHorizontal.getProgressDrawable());
     }
 
+    @UiThreadTest
     public void testAccessProgress() {
-        ProgressBar progressBar = new ProgressBar(mContext, null,
-                android.R.attr.progressBarStyleHorizontal);
-        assertEquals(0, progressBar.getProgress());
+        assertEquals(0, mProgressBarHorizontal.getProgress());
 
-        final int maxProgress = progressBar.getMax();
+        final int maxProgress = mProgressBarHorizontal.getMax();
         // set Progress
         // normal value
-        progressBar.setProgress(maxProgress >> 1);
-        assertEquals(maxProgress >> 1, progressBar.getProgress());
+        mProgressBarHorizontal.setProgress(maxProgress >> 1);
+        assertEquals(maxProgress >> 1, mProgressBarHorizontal.getProgress());
 
         // exceptional values
-        progressBar.setProgress(-1);
-        assertEquals(0, progressBar.getProgress());
+        mProgressBarHorizontal.setProgress(-1);
+        assertEquals(0, mProgressBarHorizontal.getProgress());
 
-        progressBar.setProgress(maxProgress + 1);
-        assertEquals(maxProgress, progressBar.getProgress());
+        mProgressBarHorizontal.setProgress(maxProgress + 1);
+        assertEquals(maxProgress, mProgressBarHorizontal.getProgress());
 
-        progressBar.setProgress(Integer.MAX_VALUE);
-        assertEquals(maxProgress, progressBar.getProgress());
+        mProgressBarHorizontal.setProgress(Integer.MAX_VALUE);
+        assertEquals(maxProgress, mProgressBarHorizontal.getProgress());
+
+        mProgressBarHorizontal.setProgress(0, true);
+        assertEquals(0, mProgressBarHorizontal.getProgress());
 
         // when in indeterminate mode
-        progressBar.setIndeterminate(true);
-        progressBar.setProgress(maxProgress >> 1);
-        assertEquals(0, progressBar.getProgress());
+        mProgressBarHorizontal.setIndeterminate(true);
+        mProgressBarHorizontal.setProgress(maxProgress >> 1);
+        assertEquals(0, mProgressBarHorizontal.getProgress());
     }
 
+    @UiThreadTest
     public void testAccessSecondaryProgress() {
-        ProgressBar progressBar = new ProgressBar(mContext, null,
-                android.R.attr.progressBarStyleHorizontal);
-        assertEquals(0, progressBar.getSecondaryProgress());
+        assertEquals(0, mProgressBarHorizontal.getSecondaryProgress());
 
-        final int maxProgress = progressBar.getMax();
+        final int maxProgress = mProgressBarHorizontal.getMax();
         // set SecondaryProgress
         // normal value
-        progressBar.setSecondaryProgress(maxProgress >> 1);
-        assertEquals(maxProgress >> 1, progressBar.getSecondaryProgress());
+        mProgressBarHorizontal.setSecondaryProgress(maxProgress >> 1);
+        assertEquals(maxProgress >> 1, mProgressBarHorizontal.getSecondaryProgress());
 
         // exceptional value
-        progressBar.setSecondaryProgress(-1);
-        assertEquals(0, progressBar.getSecondaryProgress());
+        mProgressBarHorizontal.setSecondaryProgress(-1);
+        assertEquals(0, mProgressBarHorizontal.getSecondaryProgress());
 
-        progressBar.setSecondaryProgress(maxProgress + 1);
-        assertEquals(maxProgress, progressBar.getSecondaryProgress());
+        mProgressBarHorizontal.setSecondaryProgress(maxProgress + 1);
+        assertEquals(maxProgress, mProgressBarHorizontal.getSecondaryProgress());
 
-        progressBar.setSecondaryProgress(Integer.MAX_VALUE);
-        assertEquals(maxProgress, progressBar.getSecondaryProgress());
+        mProgressBarHorizontal.setSecondaryProgress(Integer.MAX_VALUE);
+        assertEquals(maxProgress, mProgressBarHorizontal.getSecondaryProgress());
 
         // when in indeterminate mode
-        progressBar.setIndeterminate(true);
-        progressBar.setSecondaryProgress(maxProgress >> 1);
-        assertEquals(0, progressBar.getSecondaryProgress());
+        mProgressBarHorizontal.setIndeterminate(true);
+        mProgressBarHorizontal.setSecondaryProgress(maxProgress >> 1);
+        assertEquals(0, mProgressBarHorizontal.getSecondaryProgress());
     }
 
+    @UiThreadTest
     public void testIncrementProgressBy() {
-        ProgressBar progressBar = new ProgressBar(mContext, null,
-                android.R.attr.progressBarStyleHorizontal);
-
         // normal value
         int increment = 1;
-        int oldProgress = progressBar.getProgress();
-        progressBar.incrementProgressBy(increment);
-        assertEquals(oldProgress + increment, progressBar.getProgress());
+        int oldProgress = mProgressBarHorizontal.getProgress();
+        mProgressBarHorizontal.incrementProgressBy(increment);
+        assertEquals(oldProgress + increment, mProgressBarHorizontal.getProgress());
 
-        increment = progressBar.getMax() >> 1;
-        oldProgress = progressBar.getProgress();
-        progressBar.incrementProgressBy(increment);
-        assertEquals(oldProgress + increment, progressBar.getProgress());
+        increment = mProgressBarHorizontal.getMax() >> 1;
+        oldProgress = mProgressBarHorizontal.getProgress();
+        mProgressBarHorizontal.incrementProgressBy(increment);
+        assertEquals(oldProgress + increment, mProgressBarHorizontal.getProgress());
 
         // exceptional values
-        progressBar.setProgress(0);
-        progressBar.incrementProgressBy(Integer.MAX_VALUE);
-        assertEquals(progressBar.getMax(), progressBar.getProgress());
+        mProgressBarHorizontal.setProgress(0);
+        mProgressBarHorizontal.incrementProgressBy(Integer.MAX_VALUE);
+        assertEquals(mProgressBarHorizontal.getMax(), mProgressBarHorizontal.getProgress());
 
-        progressBar.setProgress(0);
-        progressBar.incrementProgressBy(Integer.MIN_VALUE);
-        assertEquals(0, progressBar.getProgress());
+        mProgressBarHorizontal.setProgress(0);
+        mProgressBarHorizontal.incrementProgressBy(Integer.MIN_VALUE);
+        assertEquals(0, mProgressBarHorizontal.getProgress());
     }
 
+    @UiThreadTest
     public void testIncrementSecondaryProgressBy() {
-        ProgressBar progressBar = new ProgressBar(mContext, null,
-                android.R.attr.progressBarStyleHorizontal);
-
         // normal value
         int increment = 1;
-        int oldSecondaryProgress = progressBar.getSecondaryProgress();
-        progressBar.incrementSecondaryProgressBy(increment);
-        assertEquals(oldSecondaryProgress + increment, progressBar.getSecondaryProgress());
+        int oldSecondaryProgress = mProgressBarHorizontal.getSecondaryProgress();
+        mProgressBarHorizontal.incrementSecondaryProgressBy(increment);
+        assertEquals(oldSecondaryProgress + increment,
+                mProgressBarHorizontal.getSecondaryProgress());
 
-        increment = progressBar.getMax() >> 1;
-        oldSecondaryProgress = progressBar.getSecondaryProgress();
-        progressBar.incrementSecondaryProgressBy(increment);
-        assertEquals(oldSecondaryProgress + increment, progressBar.getSecondaryProgress());
+        increment = mProgressBarHorizontal.getMax() >> 1;
+        oldSecondaryProgress = mProgressBarHorizontal.getSecondaryProgress();
+        mProgressBarHorizontal.incrementSecondaryProgressBy(increment);
+        assertEquals(oldSecondaryProgress + increment,
+                mProgressBarHorizontal.getSecondaryProgress());
 
         // exceptional values
-        progressBar.setSecondaryProgress(0);
-        progressBar.incrementSecondaryProgressBy(Integer.MAX_VALUE);
-        assertEquals(progressBar.getMax(), progressBar.getSecondaryProgress());
+        mProgressBarHorizontal.setSecondaryProgress(0);
+        mProgressBarHorizontal.incrementSecondaryProgressBy(Integer.MAX_VALUE);
+        assertEquals(mProgressBarHorizontal.getMax(),
+                mProgressBarHorizontal.getSecondaryProgress());
 
-        progressBar.setSecondaryProgress(0);
-        progressBar.incrementSecondaryProgressBy(Integer.MIN_VALUE);
-        assertEquals(0, progressBar.getSecondaryProgress());
+        mProgressBarHorizontal.setSecondaryProgress(0);
+        mProgressBarHorizontal.incrementSecondaryProgressBy(Integer.MIN_VALUE);
+        assertEquals(0, mProgressBarHorizontal.getSecondaryProgress());
     }
 
+    @UiThreadTest
     public void testAccessInterpolator() {
-        ProgressBar progressBar = new ProgressBar(mContext);
-
         // default should be LinearInterpolator
-        assertTrue(progressBar.getInterpolator() instanceof LinearInterpolator);
+        assertTrue(mProgressBar.getInterpolator() instanceof LinearInterpolator);
 
-        // normal value
-        Interpolator i = new AccelerateDecelerateInterpolator();
-        progressBar.setInterpolator(i);
-        assertEquals(i, progressBar.getInterpolator());
+        Interpolator interpolator = new AccelerateDecelerateInterpolator();
+        mProgressBar.setInterpolator(interpolator);
+        assertEquals(interpolator, mProgressBar.getInterpolator());
+
+        mProgressBar.setInterpolator(mActivity, android.R.anim.accelerate_interpolator);
+        assertTrue(mProgressBar.getInterpolator() instanceof AccelerateInterpolator);
     }
 
+    @UiThreadTest
     public void testSetVisibility() {
-        ProgressBar progressBar = new ProgressBar(mContext, null,
-                android.R.attr.progressBarStyleHorizontal);
-
         // set visibility
         // normal value
         int visibility = View.VISIBLE;
-        progressBar.setVisibility(visibility);
-        assertEquals(visibility, progressBar.getVisibility());
+        mProgressBarHorizontal.setVisibility(visibility);
+        assertEquals(visibility, mProgressBarHorizontal.getVisibility());
 
         visibility = View.GONE;
-        progressBar.setVisibility(visibility);
-        assertEquals(visibility, progressBar.getVisibility());
+        mProgressBarHorizontal.setVisibility(visibility);
+        assertEquals(visibility, mProgressBarHorizontal.getVisibility());
 
         // exceptional value
         visibility = 0xfffffff5; // -11
         int mask = 0x0000000C; // View.VISIBILITY_MASK
-        int expected = (progressBar.getVisibility() & ~mask) | (visibility & mask);
-        progressBar.setVisibility(visibility);
-        assertEquals(expected, progressBar.getVisibility());
+        int expected = (mProgressBarHorizontal.getVisibility() & ~mask) | (visibility & mask);
+        mProgressBarHorizontal.setVisibility(visibility);
+        assertEquals(expected, mProgressBarHorizontal.getVisibility());
 
         visibility = 0x7fffffff; // Integer.MAX_VALUE;
-        expected = (progressBar.getVisibility() & ~mask) | (visibility & mask);
-        progressBar.setVisibility(Integer.MAX_VALUE);
-        assertEquals(expected, progressBar.getVisibility());
+        expected = (mProgressBarHorizontal.getVisibility() & ~mask) | (visibility & mask);
+        mProgressBarHorizontal.setVisibility(Integer.MAX_VALUE);
+        assertEquals(expected, mProgressBarHorizontal.getVisibility());
     }
 
+    @UiThreadTest
     public void testInvalidateDrawable() {
-        MockProgressBar mockProgressBar = new MockProgressBar(mContext);
+        ProgressBar mockProgressBar = spy(new ProgressBar(mActivity));
 
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = spy(new ColorDrawable(Color.RED));
+        Drawable mockDrawable2 = spy(new ColorDrawable(Color.GREEN));
         mockProgressBar.setBackgroundDrawable(mockDrawable1);
 
         mockProgressBar.invalidateDrawable(mockDrawable1);
-        assertTrue(mockProgressBar.hasCalledInvalidate());
+        verify(mockProgressBar, atLeastOnce()).invalidate(anyInt(), anyInt(), anyInt(), anyInt());
 
-        mockProgressBar.reset();
+        reset(mockProgressBar);
         mockProgressBar.invalidateDrawable(mockDrawable2);
-        assertFalse(mockProgressBar.hasCalledInvalidate());
+        verify(mockProgressBar, never()).invalidate(anyInt(), anyInt(), anyInt(), anyInt());
 
         mockProgressBar.setIndeterminateDrawable(mockDrawable1);
         mockProgressBar.setProgressDrawable(mockDrawable2);
     }
 
+    @UiThreadTest
     public void testPostInvalidate() {
-        MockProgressBar mockProgressBar = new MockProgressBar(mContext);
-        mockProgressBar.postInvalidate();
+        mProgressBarHorizontal.postInvalidate();
     }
 
+    @UiThreadTest
     public void testAccessMax() {
-        ProgressBar progressBar = new ProgressBar(mContext, null,
-                android.R.attr.progressBarStyleHorizontal);
-
         // set Progress
         int progress = 10;
-        progressBar.setProgress(progress);
+        mProgressBarHorizontal.setProgress(progress);
 
         // normal value
         int max = progress + 1;
-        progressBar.setMax(max);
-        assertEquals(max, progressBar.getMax());
-        assertEquals(progress, progressBar.getProgress());
+        mProgressBarHorizontal.setMax(max);
+        assertEquals(max, mProgressBarHorizontal.getMax());
+        assertEquals(progress, mProgressBarHorizontal.getProgress());
 
         max = progress - 1;
-        progressBar.setMax(max);
-        assertEquals(max, progressBar.getMax());
-        assertEquals(max, progressBar.getProgress());
+        mProgressBarHorizontal.setMax(max);
+        assertEquals(max, mProgressBarHorizontal.getMax());
+        assertEquals(max, mProgressBarHorizontal.getProgress());
 
         // exceptional values
-        progressBar.setMax(-1);
-        assertEquals(0, progressBar.getMax());
-        assertEquals(0, progressBar.getProgress());
+        mProgressBarHorizontal.setMax(-1);
+        assertEquals(0, mProgressBarHorizontal.getMax());
+        assertEquals(0, mProgressBarHorizontal.getProgress());
 
-        progressBar.setMax(Integer.MAX_VALUE);
-        assertEquals(Integer.MAX_VALUE, progressBar.getMax());
-        assertEquals(0, progressBar.getProgress());
+        mProgressBarHorizontal.setMax(Integer.MAX_VALUE);
+        assertEquals(Integer.MAX_VALUE, mProgressBarHorizontal.getMax());
+        assertEquals(0, mProgressBarHorizontal.getProgress());
     }
 
     public void testOnDraw() {
         // Do not test, it's controlled by View. Implementation details
     }
 
+    @UiThreadTest
     public void testProgressTint() {
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-        View layout = inflater.inflate(R.layout.progressbar_layout, null);
-        ProgressBar inflatedView = (ProgressBar) layout.findViewById(R.id.progress_tint);
+        ProgressBar tintedProgressBar = (ProgressBar) mActivity.findViewById(R.id.progress_tint);
 
         assertEquals("Progress tint inflated correctly",
-                Color.WHITE, inflatedView.getProgressTintList().getDefaultColor());
+                Color.WHITE, tintedProgressBar.getProgressTintList().getDefaultColor());
         assertEquals("Progress tint mode inflated correctly",
-                PorterDuff.Mode.SRC_OVER, inflatedView.getProgressTintMode());
+                PorterDuff.Mode.SRC_OVER, tintedProgressBar.getProgressTintMode());
 
         assertEquals("Progress background tint inflated correctly",
-                Color.WHITE, inflatedView.getProgressBackgroundTintList().getDefaultColor());
+                Color.WHITE, tintedProgressBar.getProgressBackgroundTintList().getDefaultColor());
         assertEquals("Progress background tint mode inflated correctly",
-                PorterDuff.Mode.SRC_OVER, inflatedView.getProgressBackgroundTintMode());
+                PorterDuff.Mode.SRC_OVER, tintedProgressBar.getProgressBackgroundTintMode());
 
         assertEquals("Secondary progress tint inflated correctly",
-                Color.WHITE, inflatedView.getSecondaryProgressTintList().getDefaultColor());
+                Color.WHITE, tintedProgressBar.getSecondaryProgressTintList().getDefaultColor());
         assertEquals("Secondary progress tint mode inflated correctly",
-                PorterDuff.Mode.SRC_OVER, inflatedView.getSecondaryProgressTintMode());
+                PorterDuff.Mode.SRC_OVER, tintedProgressBar.getSecondaryProgressTintMode());
 
-        MockDrawable progress = new MockDrawable();
-        ProgressBar view = new ProgressBar(mContext);
+        Drawable mockProgressDrawable = spy(new ColorDrawable(Color.BLACK));
 
-        view.setProgressDrawable(progress);
-        assertFalse("No progress tint applied by default", progress.hasCalledSetTint());
+        mProgressBar.setProgressDrawable(mockProgressDrawable);
+        // No progress tint applied by default
+        verify(mockProgressDrawable, never()).setTintList(any(ColorStateList.class));
 
-        view.setProgressBackgroundTintList(ColorStateList.valueOf(Color.WHITE));
-        assertFalse("Progress background tint not applied when layer missing",
-                progress.hasCalledSetTint());
+        mProgressBar.setProgressBackgroundTintList(ColorStateList.valueOf(Color.WHITE));
+        // Progress background tint not applied when layer missing
+        verify(mockProgressDrawable, never()).setTintList(any(ColorStateList.class));
 
-        view.setSecondaryProgressTintList(ColorStateList.valueOf(Color.WHITE));
-        assertFalse("Secondary progress tint not applied when layer missing",
-                progress.hasCalledSetTint());
+        mProgressBar.setSecondaryProgressTintList(ColorStateList.valueOf(Color.WHITE));
+        // Secondary progress tint not applied when layer missing
+        verify(mockProgressDrawable, never()).setTintList(any(ColorStateList.class));
 
-        view.setProgressTintList(ColorStateList.valueOf(Color.WHITE));
-        assertTrue("Progress tint applied when setProgressTintList() called after setProgress()",
-                progress.hasCalledSetTint());
+        mProgressBar.setProgressTintList(ColorStateList.valueOf(Color.WHITE));
+        // Progress tint applied when setProgressTintList() called after setProgress()
+        verify(mockProgressDrawable, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
 
-        progress.reset();
-        view.setProgressDrawable(null);
-        view.setProgressDrawable(progress);
-        assertTrue("Progress tint applied when setProgressTintList() called before setProgress()",
-                progress.hasCalledSetTint());
+        mProgressBar.setProgressBackgroundTintMode(PorterDuff.Mode.DST_OVER);
+        assertEquals(PorterDuff.Mode.DST_OVER, mProgressBar.getProgressBackgroundTintMode());
+
+        mProgressBar.setSecondaryProgressTintMode(PorterDuff.Mode.DST_IN);
+        assertEquals(PorterDuff.Mode.DST_IN, mProgressBar.getSecondaryProgressTintMode());
+
+        mProgressBar.setProgressTintMode(PorterDuff.Mode.DST_ATOP);
+        assertEquals(PorterDuff.Mode.DST_ATOP, mProgressBar.getProgressTintMode());
+
+        reset(mockProgressDrawable);
+        mProgressBar.setProgressDrawable(null);
+        mProgressBar.setProgressDrawable(mockProgressDrawable);
+        // Progress tint applied when setProgressTintList() called before setProgress()
+        verify(mockProgressDrawable, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
     }
 
+    @UiThreadTest
     public void testIndeterminateTint() {
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-        View layout = inflater.inflate(R.layout.progressbar_layout, null);
-        ProgressBar inflatedView = (ProgressBar) layout.findViewById(R.id.indeterminate_tint);
+        ProgressBar tintedProgressBar =
+                (ProgressBar) mActivity.findViewById(R.id.indeterminate_tint);
 
         assertEquals("Indeterminate tint inflated correctly",
-                Color.WHITE, inflatedView.getIndeterminateTintList().getDefaultColor());
+                Color.WHITE, tintedProgressBar.getIndeterminateTintList().getDefaultColor());
         assertEquals("Indeterminate tint mode inflated correctly",
-                PorterDuff.Mode.SRC_OVER, inflatedView.getIndeterminateTintMode());
+                PorterDuff.Mode.SRC_OVER, tintedProgressBar.getIndeterminateTintMode());
 
-        MockDrawable indeterminate = new MockDrawable();
-        ProgressBar view = new ProgressBar(mContext);
+        Drawable mockIndeterminateDrawable = spy(new ColorDrawable(Color.MAGENTA));
 
-        view.setIndeterminateDrawable(indeterminate);
-        assertFalse("No indeterminate tint applied by default", indeterminate.hasCalledSetTint());
+        mProgressBar.setIndeterminateDrawable(mockIndeterminateDrawable);
+        // No indeterminate tint applied by default
+        verify(mockIndeterminateDrawable, never()).setTintList(any(ColorStateList.class));
 
-        view.setIndeterminateTintList(ColorStateList.valueOf(Color.WHITE));
-        assertTrue("Indeterminate tint applied when setIndeterminateTintList() called after "
-                + "setIndeterminate()", indeterminate.hasCalledSetTint());
+        mProgressBar.setIndeterminateTintList(ColorStateList.valueOf(Color.RED));
+        // Indeterminate tint applied when setIndeterminateTintList() called after
+        // setIndeterminate()
+        verify(mockIndeterminateDrawable, times(1)).setTintList(
+                TestUtils.colorStateListOf(Color.RED));
 
-        indeterminate.reset();
-        view.setIndeterminateDrawable(null);
-        view.setIndeterminateDrawable(indeterminate);
-        assertTrue("Indeterminate tint applied when setIndeterminateTintList() called before "
-                + "setIndeterminate()", indeterminate.hasCalledSetTint());
-    }
+        mProgressBar.setIndeterminateTintMode(PorterDuff.Mode.LIGHTEN);
+        assertEquals(PorterDuff.Mode.LIGHTEN, mProgressBar.getIndeterminateTintMode());
 
-    private class MockDrawable extends Drawable {
-        private boolean mCalledDraw = false;
-        private boolean mCalledSetTint = false;
-
-        @Override
-        public void draw(Canvas canvas) {
-            mCalledDraw = true;
-        }
-
-        @Override
-        public int getOpacity() {
-            return 0;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-        }
-
-        @Override
-        public void setTintList(ColorStateList tint) {
-            super.setTintList(tint);
-            mCalledSetTint = true;
-        }
-
-        public boolean hasCalledSetTint() {
-            return mCalledSetTint;
-        }
-
-        public boolean hasCalledDraw() {
-            return mCalledDraw;
-        }
-
-        public void reset() {
-            mCalledDraw = false;
-            mCalledSetTint = false;
-        }
-
+        reset(mockIndeterminateDrawable);
+        mProgressBar.setIndeterminateDrawable(null);
+        mProgressBar.setIndeterminateDrawable(mockIndeterminateDrawable);
+        // Indeterminate tint applied when setIndeterminateTintList() called before
+        // setIndeterminate()
+        verify(mockIndeterminateDrawable, times(1)).setTintList(
+                TestUtils.colorStateListOf(Color.RED));
     }
 
     public void testOnMeasure() {
@@ -432,13 +469,14 @@
         // onSizeChanged() is implementation details, do NOT test
     }
 
+    @UiThreadTest
     public void testVerifyDrawable() {
-        MockProgressBar mockProgressBar = new MockProgressBar(mContext);
+        MockProgressBar mockProgressBar = new MockProgressBar(mActivity);
         assertTrue(mockProgressBar.verifyDrawable(null));
 
-        Drawable d1 = mContext.getResources().getDrawable(R.drawable.blue);
-        Drawable d2 = mContext.getResources().getDrawable(R.drawable.red);
-        Drawable d3 = mContext.getResources().getDrawable(R.drawable.yellow);
+        Drawable d1 = mActivity.getResources().getDrawable(R.drawable.blue);
+        Drawable d2 = mActivity.getResources().getDrawable(R.drawable.red);
+        Drawable d3 = mActivity.getResources().getDrawable(R.drawable.yellow);
 
         mockProgressBar.setBackgroundDrawable(d1);
         assertTrue(mockProgressBar.verifyDrawable(null));
@@ -463,39 +501,33 @@
         // drawableStateChanged() is implementation details, do NOT test
     }
 
+    @UiThreadTest
     public void testOnSaveAndRestoreInstanceState() {
-        ProgressBar progressBar = new ProgressBar(mContext, null,
-                android.R.attr.progressBarStyleHorizontal);
         int oldProgress = 1;
-        int oldSecondaryProgress = progressBar.getMax() - 1;
-        progressBar.setProgress(oldProgress);
-        progressBar.setSecondaryProgress(oldSecondaryProgress);
-        assertEquals(oldProgress, progressBar.getProgress());
-        assertEquals(oldSecondaryProgress, progressBar.getSecondaryProgress());
+        int oldSecondaryProgress = mProgressBarHorizontal.getMax() - 1;
+        mProgressBarHorizontal.setProgress(oldProgress);
+        mProgressBarHorizontal.setSecondaryProgress(oldSecondaryProgress);
+        assertEquals(oldProgress, mProgressBarHorizontal.getProgress());
+        assertEquals(oldSecondaryProgress, mProgressBarHorizontal.getSecondaryProgress());
 
-        Parcelable state = progressBar.onSaveInstanceState();
+        Parcelable state = mProgressBarHorizontal.onSaveInstanceState();
 
         int newProgress = 2;
-        int newSecondaryProgress = progressBar.getMax() - 2;
-        progressBar.setProgress(newProgress);
-        progressBar.setSecondaryProgress(newSecondaryProgress);
-        assertEquals(newProgress, progressBar.getProgress());
-        assertEquals(newSecondaryProgress, progressBar.getSecondaryProgress());
+        int newSecondaryProgress = mProgressBarHorizontal.getMax() - 2;
+        mProgressBarHorizontal.setProgress(newProgress);
+        mProgressBarHorizontal.setSecondaryProgress(newSecondaryProgress);
+        assertEquals(newProgress, mProgressBarHorizontal.getProgress());
+        assertEquals(newSecondaryProgress, mProgressBarHorizontal.getSecondaryProgress());
 
-        progressBar.onRestoreInstanceState(state);
-        assertEquals(oldProgress, progressBar.getProgress());
-        assertEquals(oldSecondaryProgress, progressBar.getSecondaryProgress());
+        mProgressBarHorizontal.onRestoreInstanceState(state);
+        assertEquals(oldProgress, mProgressBarHorizontal.getProgress());
+        assertEquals(oldSecondaryProgress, mProgressBarHorizontal.getSecondaryProgress());
     }
 
     /*
      * Mock class for ProgressBar to test protected methods
      */
     private class MockProgressBar extends ProgressBar {
-        private boolean mCalledInvalidate = false;
-
-        /**
-         * @param context
-         */
         public MockProgressBar(Context context) {
             super(context);
         }
@@ -504,44 +536,5 @@
         protected boolean verifyDrawable(Drawable who) {
             return super.verifyDrawable(who);
         }
-
-        @Override
-        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-            super.onSizeChanged(w, h, oldw, oldh);
-        }
-
-        @Override
-        protected synchronized void onMeasure(int widthMeasureSpec,
-                int heightMeasureSpec) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-
-        @Override
-        protected synchronized void onDraw(Canvas canvas) {
-            super.onDraw(canvas);
-        }
-
-        @Override
-        protected void drawableStateChanged() {
-            super.drawableStateChanged();
-        }
-
-        public void invalidate(int l, int t, int r, int b) {
-            mCalledInvalidate = true;
-            super.invalidate(l, t, r, b);
-        }
-
-        public void invalidate() {
-            mCalledInvalidate = true;
-            super.invalidate();
-        }
-
-        public boolean hasCalledInvalidate() {
-            return mCalledInvalidate;
-        }
-
-        public void reset() {
-            mCalledInvalidate = false;
-        }
     }
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/RadioButtonCtsActivity.java
similarity index 67%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/RadioButtonCtsActivity.java
index 481f5be..442d5f7 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioButtonCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.RadioButton;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link RadioButton} test.
+ */
+public class RadioButtonCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.radiobutton_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java b/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
index eb9387b..7884401 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
@@ -16,67 +16,167 @@
 
 package android.widget.cts;
 
+import static org.mockito.Mockito.*;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.cts.util.CtsTouchUtils;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+import android.widget.RadioButton;
 import android.widget.cts.R;
 
+@SmallTest
+public class RadioButtonTest extends ActivityInstrumentationTestCase2<RadioButtonCtsActivity> {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private RadioButton mRadioButton;
 
-import android.content.Context;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.util.AttributeSet;
-import android.widget.RadioButton;
-
-/**
- * Test {@link RadioButton}.
- */
-public class RadioButtonTest extends InstrumentationTestCase {
-    private Context mContext;
+    public RadioButtonTest() {
+        super("android.widget.cts", RadioButtonCtsActivity.class);
+    }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+        mRadioButton = (RadioButton) mActivity.findViewById(R.id.radio_button);
     }
 
     public void testConstructor() {
-        AttributeSet attrs = mContext.getResources().getLayout(R.layout.radiogroup_1);
-        assertNotNull(attrs);
+        new RadioButton(mActivity);
+        new RadioButton(mActivity, null);
+        new RadioButton(mActivity, null, android.R.attr.radioButtonStyle);
+        new RadioButton(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_CompoundButton_RadioButton);
+        new RadioButton(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_CompoundButton_RadioButton);
+        new RadioButton(mActivity, null, 0,
+                android.R.style.Widget_Material_CompoundButton_RadioButton);
+        new RadioButton(mActivity, null, 0,
+                android.R.style.Widget_Material_Light_CompoundButton_RadioButton);
 
-        new RadioButton(mContext);
         try {
             new RadioButton(null);
             fail("The constructor should throw NullPointerException when param Context is null.");
         } catch (NullPointerException e) {
         }
 
-        new RadioButton(mContext, attrs);
         try {
-            new RadioButton(null, attrs);
+            new RadioButton(null, null);
             fail("The constructor should throw NullPointerException when param Context is null.");
         } catch (NullPointerException e) {
         }
-        new RadioButton(mContext, null);
-
-        new RadioButton(mContext, attrs, 0);
         try {
-            new RadioButton(null, attrs, 0);
+            new RadioButton(null, null, 0);
             fail("The constructor should throw NullPointerException when param Context is null.");
         } catch (NullPointerException e) {
         }
-        new RadioButton(mContext, null, 0);
-        new RadioButton(mContext, attrs, Integer.MAX_VALUE);
-        new RadioButton(mContext, attrs, Integer.MIN_VALUE);
     }
 
-    @UiThreadTest
-    public void testToggle() {
-        RadioButton button = new RadioButton(mContext);
-        assertFalse(button.isChecked());
+    public void testText() {
+        assertTrue(TextUtils.equals(
+                mActivity.getString(R.string.hello_world), mRadioButton.getText()));
 
-        button.toggle();
-        assertTrue(button.isChecked());
+        mInstrumentation.runOnMainSync(() -> mRadioButton.setText("new text"));
+        assertTrue(TextUtils.equals("new text", mRadioButton.getText()));
 
-        // Can't be toggled if it is checked
-        button.toggle();
-        assertTrue(button.isChecked());
+        mInstrumentation.runOnMainSync(() -> mRadioButton.setText(R.string.text_name));
+        assertTrue(TextUtils.equals(
+                mActivity.getString(R.string.text_name), mRadioButton.getText()));
+    }
+
+    public void testAccessChecked() {
+        final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(RadioButton.OnCheckedChangeListener.class);
+        mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mRadioButton.isChecked());
+
+        // not checked -> not checked
+        mInstrumentation.runOnMainSync(() -> mRadioButton.setChecked(false));
+        verifyZeroInteractions(mockCheckedChangeListener);
+        assertFalse(mRadioButton.isChecked());
+
+        // not checked -> checked
+        mInstrumentation.runOnMainSync(() -> mRadioButton.setChecked(true));
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+        assertTrue(mRadioButton.isChecked());
+
+        // checked -> checked
+        mInstrumentation.runOnMainSync(() -> mRadioButton.setChecked(true));
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+        assertTrue(mRadioButton.isChecked());
+
+        // checked -> not checked
+        mInstrumentation.runOnMainSync(() -> mRadioButton.setChecked(false));
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, false);
+        assertFalse(mRadioButton.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
+    }
+
+    public void testToggleViaApi() {
+        final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(RadioButton.OnCheckedChangeListener.class);
+        mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mRadioButton.isChecked());
+
+        // toggle to checked
+        mInstrumentation.runOnMainSync(mRadioButton::toggle);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+        assertTrue(mRadioButton.isChecked());
+
+        // try toggle to not checked - this should leave the radio button in checked state
+        mInstrumentation.runOnMainSync(mRadioButton::toggle);
+        assertTrue(mRadioButton.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
+    }
+
+    public void testToggleViaEmulatedTap() {
+        final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(RadioButton.OnCheckedChangeListener.class);
+        mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mRadioButton.isChecked());
+
+        // tap to checked
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mRadioButton);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+        assertTrue(mRadioButton.isChecked());
+
+        // tap to not checked - this should leave the radio button in checked state
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mRadioButton);
+        assertTrue(mRadioButton.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
+    }
+
+    public void testToggleViaPerformClick() {
+        final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(RadioButton.OnCheckedChangeListener.class);
+        mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mRadioButton.isChecked());
+
+        // click to checked
+        mInstrumentation.runOnMainSync(mRadioButton::performClick);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+        assertTrue(mRadioButton.isChecked());
+
+        // click to not checked - this should leave the radio button in checked state
+        mInstrumentation.runOnMainSync(mRadioButton::performClick);
+        assertTrue(mRadioButton.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java b/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
index b2154e2..73b0996 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
@@ -16,12 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.content.Context;
 import android.test.InstrumentationTestCase;
 import android.test.UiThreadTest;
@@ -34,9 +28,13 @@
 import android.widget.LinearLayout;
 import android.widget.RadioButton;
 import android.widget.RadioGroup;
-import android.widget.RelativeLayout;
 import android.widget.RadioGroup.LayoutParams;
 import android.widget.RadioGroup.OnCheckedChangeListener;
+import android.widget.RelativeLayout;
+import android.widget.cts.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.util.Vector;
diff --git a/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java
index 37cd632..eded48d 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java
@@ -17,11 +17,6 @@
 package android.widget.cts;
 
 import android.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.test.AndroidTestCase;
@@ -33,6 +28,9 @@
 import android.widget.RadioGroup;
 import android.widget.RadioGroup.LayoutParams;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
 /**
diff --git a/tests/tests/widget/src/android/widget/cts/RatingBarCtsActivity.java b/tests/tests/widget/src/android/widget/cts/RatingBarCtsActivity.java
index 1a9cb40..aea46a0 100644
--- a/tests/tests/widget/src/android/widget/cts/RatingBarCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/RatingBarCtsActivity.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-
 import android.widget.cts.R;
 
 /**
diff --git a/tests/tests/widget/src/android/widget/cts/RatingBarTest.java b/tests/tests/widget/src/android/widget/cts/RatingBarTest.java
index 669e7a1..db4a4e6 100644
--- a/tests/tests/widget/src/android/widget/cts/RatingBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RatingBarTest.java
@@ -16,20 +16,21 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.mockito.Mockito.*;
 
-import android.content.Context;
+import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.RatingBar;
-import android.widget.RatingBar.OnRatingBarChangeListener;
 
 /**
  * Test {@link RatingBar}.
  */
+@SmallTest
 public class RatingBarTest extends ActivityInstrumentationTestCase2<RatingBarCtsActivity> {
-    private Context mContext;
+    private Instrumentation mInstrumentation;
     private RatingBarCtsActivity mActivity;
+    private RatingBar mRatingBar;
 
     public RatingBarTest() {
         super("android.widget.cts", RatingBarCtsActivity.class);
@@ -38,213 +39,137 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        mInstrumentation = getInstrumentation();
         mActivity = getActivity();
-        assertNotNull(mActivity);
-        mContext = getInstrumentation().getContext();
+        mRatingBar = (RatingBar) mActivity.findViewById(R.id.ratingbar_constructor);
     }
 
     public void testConstructor() {
-        new RatingBar(mContext, null, android.R.attr.ratingBarStyle);
-
-        new RatingBar(mContext, null);
-
-        new RatingBar(mContext);
-
-        RatingBar ratingBar = (RatingBar) mActivity.findViewById(R.id.ratingbar_constructor);
-        assertNotNull(ratingBar);
-        assertFalse(ratingBar.isIndicator());
-        assertEquals(50, ratingBar.getNumStars());
-        assertEquals(1.2f, ratingBar.getRating());
-        assertEquals(0.2f, ratingBar.getStepSize());
+        new RatingBar(mActivity);
+        new RatingBar(mActivity, null);
+        new RatingBar(mActivity, null, android.R.attr.ratingBarStyle);
+        new RatingBar(mActivity, null, 0, android.R.style.Widget_DeviceDefault_RatingBar);
+        new RatingBar(mActivity, null, 0, android.R.style.Widget_DeviceDefault_RatingBar_Indicator);
+        new RatingBar(mActivity, null, 0, android.R.style.Widget_DeviceDefault_RatingBar_Small);
+        new RatingBar(mActivity, null, 0, android.R.style.Widget_Material_RatingBar);
+        new RatingBar(mActivity, null, 0, android.R.style.Widget_Material_RatingBar_Indicator);
+        new RatingBar(mActivity, null, 0, android.R.style.Widget_Material_RatingBar_Small);
+        new RatingBar(mActivity, null, 0, android.R.style.Widget_Material_Light_RatingBar);
+        new RatingBar(mActivity, null, 0, android.R.style.Widget_Material_Light_RatingBar_Indicator);
+        new RatingBar(mActivity, null, 0, android.R.style.Widget_Material_Light_RatingBar_Small);
     }
 
-    @UiThreadTest
+    public void testAttributesFromLayout() {
+        assertFalse(mRatingBar.isIndicator());
+        assertEquals(50, mRatingBar.getNumStars());
+        assertEquals(1.2f, mRatingBar.getRating());
+        assertEquals(0.2f, mRatingBar.getStepSize());
+    }
+
     public void testAccessOnRatingBarChangeListener() {
-        RatingBar ratingBar = (RatingBar)mActivity.findViewById(R.id.ratingbar_constructor);
+        final RatingBar.OnRatingBarChangeListener listener =
+                mock(RatingBar.OnRatingBarChangeListener.class);
+        mRatingBar.setOnRatingBarChangeListener(listener);
+        assertSame(listener, mRatingBar.getOnRatingBarChangeListener());
+        verifyZeroInteractions(listener);
 
-        MockOnRatingBarChangeListener listener = new MockOnRatingBarChangeListener();
-
-        // set OnRatingBarChangeListener
         // normal value
-        ratingBar.setOnRatingBarChangeListener(listener);
-        assertSame(listener, ratingBar.getOnRatingBarChangeListener());
-        ratingBar.setRating(2.2f);
-        assertTrue(listener.hasCalledOnRatingChanged());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setRating(2.2f));
+        verify(listener, times(1)).onRatingChanged(mRatingBar, 2.2f, false);
 
         // exceptional value
-        listener.reset();
-        ratingBar.setOnRatingBarChangeListener(null);
-        assertNull(ratingBar.getOnRatingBarChangeListener());
-        ratingBar.setRating(1.2f);
-        assertFalse(listener.hasCalledOnRatingChanged());
+        mRatingBar.setOnRatingBarChangeListener(null);
+        assertNull(mRatingBar.getOnRatingBarChangeListener());
+        mRatingBar.setRating(1.2f);
+        verifyNoMoreInteractions(listener);
     }
 
     public void testAccessIndicator() {
-        RatingBar ratingBar = new RatingBar(mContext);
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setIsIndicator(true));
+        assertTrue(mRatingBar.isIndicator());
 
-        ratingBar.setIsIndicator(true);
-        assertTrue(ratingBar.isIndicator());
-
-        ratingBar.setIsIndicator(false);
-        assertFalse(ratingBar.isIndicator());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setIsIndicator(false));
+        assertFalse(mRatingBar.isIndicator());
     }
 
     public void testAccessNumStars() {
-        MockRatingBar mockRatingBar = new MockRatingBar(mContext);
-
         // set NumStars
         // normal value
-        assertFalse(mockRatingBar.hasCalledRequestLayout());
-        mockRatingBar.setNumStars(20);
-        assertTrue(mockRatingBar.hasCalledRequestLayout());
-        assertEquals(20, mockRatingBar.getNumStars());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setNumStars(20));
+        assertEquals(20, mRatingBar.getNumStars());
 
-        // exceptional value
-        mockRatingBar.reset();
-        mockRatingBar.setNumStars(-10);
-        assertFalse(mockRatingBar.hasCalledRequestLayout());
-        assertEquals(20, mockRatingBar.getNumStars());
+        // invalid value - the currently set one stays
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setNumStars(-10));
+        assertEquals(20, mRatingBar.getNumStars());
 
-        mockRatingBar.reset();
-        mockRatingBar.setNumStars(Integer.MAX_VALUE);
-        assertTrue(mockRatingBar.hasCalledRequestLayout());
-        assertEquals(Integer.MAX_VALUE, mockRatingBar.getNumStars());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setNumStars(Integer.MAX_VALUE));
+        assertEquals(Integer.MAX_VALUE, mRatingBar.getNumStars());
     }
 
     public void testAccessRating() {
-        RatingBar ratingBar = new RatingBar(mContext);
-
         // set Rating
         // normal value
-        ratingBar.setRating(2.0f);
-        assertEquals(2.0f, ratingBar.getRating());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setRating(2.0f));
+        assertEquals(2.0f, mRatingBar.getRating());
 
         // exceptional value
-        ratingBar.setRating(-2.0f);
-        assertEquals(0f, ratingBar.getRating());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setRating(-2.0f));
+        assertEquals(0f, mRatingBar.getRating());
 
-        ratingBar.setRating(Float.MAX_VALUE);
-        assertEquals((float) ratingBar.getNumStars(), ratingBar.getRating());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setRating(Float.MAX_VALUE));
+        assertEquals((float) mRatingBar.getNumStars(), mRatingBar.getRating());
     }
 
     public void testSetMax() {
-        RatingBar ratingBar = new RatingBar(mContext);
-
         // normal value
-        ratingBar.setMax(10);
-        assertEquals(10, ratingBar.getMax());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setMax(10));
+        assertEquals(10, mRatingBar.getMax());
 
-        ratingBar.setProgress(10);
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setProgress(10));
 
         // exceptional values
-        ratingBar.setMax(-10);
-        assertEquals(10, ratingBar.getMax());
-        assertEquals(10, ratingBar.getProgress());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setMax(-10));
+        assertEquals(10, mRatingBar.getMax());
+        assertEquals(10, mRatingBar.getProgress());
 
-        ratingBar.setMax(Integer.MAX_VALUE);
-        assertEquals(Integer.MAX_VALUE, ratingBar.getMax());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setMax(Integer.MAX_VALUE));
+        assertEquals(Integer.MAX_VALUE, mRatingBar.getMax());
     }
 
     public void testAccessStepSize() {
-        RatingBar ratingBar = new RatingBar(mContext);
-
         // normal value
-        ratingBar.setStepSize(1.5f);
-        float expectedMax = ratingBar.getNumStars() / ratingBar.getStepSize();
-        float expectedProgress = expectedMax / ratingBar.getMax() * ratingBar.getProgress();
-        assertEquals((int) expectedMax, ratingBar.getMax());
-        assertEquals((int) expectedProgress, ratingBar.getProgress());
-        assertEquals((float) ratingBar.getNumStars() / (int) (ratingBar.getNumStars() / 1.5f),
-                ratingBar.getStepSize());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setStepSize(1.5f));
+        final float expectedMax = mRatingBar.getNumStars() / mRatingBar.getStepSize();
+        final float expectedProgress = expectedMax / mRatingBar.getMax() * mRatingBar.getProgress();
+        assertEquals((int) expectedMax, mRatingBar.getMax());
+        assertEquals((int) expectedProgress, mRatingBar.getProgress());
+        assertEquals((float) mRatingBar.getNumStars() / (int) (mRatingBar.getNumStars() / 1.5f),
+                mRatingBar.getStepSize());
 
-        int currentMax = ratingBar.getMax();
-        int currentProgress = ratingBar.getProgress();
-        float currentStepSize = ratingBar.getStepSize();
+        final int currentMax = mRatingBar.getMax();
+        final int currentProgress = mRatingBar.getProgress();
+        final float currentStepSize = mRatingBar.getStepSize();
         // exceptional value
-        ratingBar.setStepSize(-1.5f);
-        assertEquals(currentMax, ratingBar.getMax());
-        assertEquals(currentProgress, ratingBar.getProgress());
-        assertEquals(currentStepSize, ratingBar.getStepSize());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setStepSize(-1.5f));
+        assertEquals(currentMax, mRatingBar.getMax());
+        assertEquals(currentProgress, mRatingBar.getProgress());
+        assertEquals(currentStepSize, mRatingBar.getStepSize());
 
-        ratingBar.setStepSize(0f);
-        assertEquals(currentMax, ratingBar.getMax());
-        assertEquals(currentProgress, ratingBar.getProgress());
-        assertEquals(currentStepSize, ratingBar.getStepSize());
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setStepSize(0f));
+        assertEquals(currentMax, mRatingBar.getMax());
+        assertEquals(currentProgress, mRatingBar.getProgress());
+        assertEquals(currentStepSize, mRatingBar.getStepSize());
 
-        ratingBar.setStepSize(ratingBar.getNumStars() + 0.1f);
-        assertEquals(currentMax, ratingBar.getMax());
-        assertEquals(currentProgress, ratingBar.getProgress());
-        assertEquals(currentStepSize, ratingBar.getStepSize());
+        mInstrumentation.runOnMainSync(
+                () -> mRatingBar.setStepSize(mRatingBar.getNumStars() + 0.1f));
+        assertEquals(currentMax, mRatingBar.getMax());
+        assertEquals(currentProgress, mRatingBar.getProgress());
+        assertEquals(currentStepSize, mRatingBar.getStepSize());
 
-        ratingBar.setStepSize(Float.MAX_VALUE);
-        assertEquals(currentMax, ratingBar.getMax());
-        assertEquals(currentProgress, ratingBar.getProgress());
-        assertEquals(currentStepSize, ratingBar.getStepSize());
-    }
-
-    /**
-     * The listener interface for receiving OnRatingBarChangeListener events.
-     * The class that is interested in processing a OnRatingBarChangeListener
-     * event implements this interface, and the object created with that class
-     * is registered with a component using the component's
-     * <code>setOnRatingBarChangeListener<code> method. When
-     * the OnRatingBarChangeListener event occurs, that object's appropriate
-     * method is invoked.
-     */
-    private class MockOnRatingBarChangeListener implements OnRatingBarChangeListener {
-        private boolean mCalledOnRatingChanged = false;
-
-        boolean hasCalledOnRatingChanged() {
-            return mCalledOnRatingChanged;
-        }
-
-        /*
-         * (non-Javadoc)
-         * @see android.widget.RadioGroup.OnRatingBarChangeListener#onRatingChanged
-         * (RatingBar ratingBar, float rating, boolean fromTouch)
-         */
-        public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromTouch) {
-            mCalledOnRatingChanged = true;
-        }
-
-        public void reset() {
-            mCalledOnRatingChanged = false;
-        }
-    }
-
-    /*
-     * Mock class for ProgressBar to test protected methods
-     */
-    private class MockRatingBar extends RatingBar {
-        public MockRatingBar(Context context) {
-            super(context);
-        }
-
-        private boolean mCalledOnMeasure = false;
-        private boolean mCalledRequestLayout = false;
-
-        public boolean hasCalledOnMeasure() {
-            return mCalledOnMeasure;
-        }
-
-        @Override
-        protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            mCalledOnMeasure = true;
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-
-        public void requestLayout() {
-            mCalledRequestLayout = true;
-            super.requestLayout();
-        }
-
-        public boolean hasCalledRequestLayout() {
-            return mCalledRequestLayout;
-        }
-
-        public void reset() {
-            mCalledOnMeasure = false;
-            mCalledRequestLayout = false;
-        }
+        mInstrumentation.runOnMainSync(() -> mRatingBar.setStepSize(Float.MAX_VALUE));
+        assertEquals(currentMax, mRatingBar.getMax());
+        assertEquals(currentProgress, mRatingBar.getProgress());
+        assertEquals(currentStepSize, mRatingBar.getStepSize());
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/RelativeLayoutCtsActivity.java b/tests/tests/widget/src/android/widget/cts/RelativeLayoutCtsActivity.java
index c394ca4..15d5924 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayoutCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayoutCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 /**
  * A minimal application for RelativeLayout test.
diff --git a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
index 2f3be6f..db7f04c8 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
@@ -16,12 +16,8 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
 import android.content.res.XmlResourceParser;
 import android.test.ActivityInstrumentationTestCase2;
@@ -34,8 +30,12 @@
 import android.view.ViewGroup.LayoutParams;
 import android.widget.AbsListView;
 import android.widget.RelativeLayout;
+import android.widget.cts.R;
 import android.widget.cts.util.XmlUtils;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
 /**
@@ -43,6 +43,7 @@
  */
 public class RelativeLayoutTest extends
         ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
 
     public RelativeLayoutTest() {
@@ -52,6 +53,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        mInstrumentation = getInstrumentation();
         mActivity = getActivity();
     }
 
@@ -86,27 +89,19 @@
         ViewAsserts.assertRightAligned(relativeLayout, view13);
 
         relativeLayout.setIgnoreGravity(R.id.relative_view13);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.requestLayout();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(relativeLayout::requestLayout);
+        mInstrumentation.waitForIdleSync();
         ViewAsserts.assertRightAligned(relativeLayout, view12);
         ViewAsserts.assertLeftAligned(relativeLayout, view13);
 
         relativeLayout.setIgnoreGravity(0);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.requestLayout();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(relativeLayout::requestLayout);
+        mInstrumentation.waitForIdleSync();
         ViewAsserts.assertRightAligned(relativeLayout, view12);
         ViewAsserts.assertRightAligned(relativeLayout, view13);
     }
 
-    public void testSetGravity() {
+    public void testAccessGravity() {
         final RelativeLayout relativeLayout = (RelativeLayout) mActivity.findViewById(
                 R.id.relative_sublayout_gravity);
 
@@ -120,48 +115,38 @@
         assertEquals(view11.getTop(), view10.getBottom());
 
         // -- BOTTOM && RIGHT
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setGravity(Gravity.BOTTOM | Gravity.RIGHT);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(
+                () -> relativeLayout.setGravity(Gravity.BOTTOM | Gravity.RIGHT));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(Gravity.BOTTOM | Gravity.RIGHT, relativeLayout.getGravity());
         ViewAsserts.assertRightAligned(relativeLayout, view10);
         assertEquals(view11.getTop(), view10.getBottom());
         ViewAsserts.assertRightAligned(relativeLayout, view11);
         ViewAsserts.assertBottomAligned(relativeLayout, view11);
 
         // -- BOTTOM
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setGravity(Gravity.BOTTOM);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> relativeLayout.setGravity(Gravity.BOTTOM));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(Gravity.BOTTOM | Gravity.START, relativeLayout.getGravity());
         ViewAsserts.assertLeftAligned(relativeLayout, view10);
         assertEquals(view11.getTop(), view10.getBottom());
         ViewAsserts.assertLeftAligned(relativeLayout, view11);
         ViewAsserts.assertBottomAligned(relativeLayout, view11);
 
         // CENTER_HORIZONTAL
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setGravity(Gravity.CENTER_HORIZONTAL);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> relativeLayout.setGravity(Gravity.CENTER_HORIZONTAL));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(Gravity.CENTER_HORIZONTAL | Gravity.TOP,
+                relativeLayout.getGravity());
         ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view10);
         ViewAsserts.assertTopAligned(relativeLayout, view10);
         ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view11);
         assertEquals(view11.getTop(), view10.getBottom());
 
         // CENTER_VERTICAL
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setGravity(Gravity.CENTER_VERTICAL);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> relativeLayout.setGravity(Gravity.CENTER_VERTICAL));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(Gravity.CENTER_VERTICAL | Gravity.START, relativeLayout.getGravity());
         ViewAsserts.assertLeftAligned(relativeLayout, view10);
         int topSpace = view10.getTop();
         int bottomSpace = relativeLayout.getHeight() - view11.getBottom();
@@ -184,24 +169,20 @@
         assertEquals(view11.getTop(), view10.getBottom());
 
         // RIGHT
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setHorizontalGravity(Gravity.RIGHT);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> relativeLayout.setHorizontalGravity(Gravity.RIGHT));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(Gravity.RIGHT, Gravity.HORIZONTAL_GRAVITY_MASK & relativeLayout.getGravity());
         ViewAsserts.assertRightAligned(relativeLayout, view10);
         ViewAsserts.assertTopAligned(relativeLayout, view10);
         ViewAsserts.assertRightAligned(relativeLayout, view11);
         assertEquals(view11.getTop(), view10.getBottom());
 
         // CENTER_HORIZONTAL
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setHorizontalGravity(Gravity.CENTER_HORIZONTAL);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(
+                () -> relativeLayout.setHorizontalGravity(Gravity.CENTER_HORIZONTAL));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(Gravity.CENTER_HORIZONTAL,
+                Gravity.HORIZONTAL_GRAVITY_MASK & relativeLayout.getGravity());
         ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view10);
         ViewAsserts.assertTopAligned(relativeLayout, view10);
         ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view11);
@@ -222,24 +203,20 @@
         assertEquals(view11.getTop(), view10.getBottom());
 
         // BOTTOM
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setVerticalGravity(Gravity.BOTTOM);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> relativeLayout.setVerticalGravity(Gravity.BOTTOM));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(Gravity.BOTTOM, Gravity.VERTICAL_GRAVITY_MASK & relativeLayout.getGravity());
         ViewAsserts.assertLeftAligned(relativeLayout, view10);
         assertEquals(view11.getTop(), view10.getBottom());
         ViewAsserts.assertLeftAligned(relativeLayout, view11);
         ViewAsserts.assertBottomAligned(relativeLayout, view11);
 
         // CENTER_VERTICAL
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setVerticalGravity(Gravity.CENTER_VERTICAL);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(
+                () -> relativeLayout.setVerticalGravity(Gravity.CENTER_VERTICAL));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(Gravity.CENTER_VERTICAL,
+                Gravity.VERTICAL_GRAVITY_MASK & relativeLayout.getGravity());
         ViewAsserts.assertLeftAligned(relativeLayout, view10);
         int topSpace = view10.getTop();
         int bottomSpace = relativeLayout.getHeight() - view11.getBottom();
@@ -352,12 +329,9 @@
      * Tests to prevent regressions in baseline alignment.
      */
     public void testBaselineAlignment() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(R.layout.relative_layout_baseline);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.runOnMainSync(
+                () -> mActivity.setContentView(R.layout.relative_layout_baseline));
+        mInstrumentation.waitForIdleSync();
 
         View button = mActivity.findViewById(R.id.button1);
         assertTrue(button.getHeight() > 0);
diff --git a/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java
index 5706781..30f07da 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java
@@ -16,26 +16,40 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
+import android.app.Activity;
+import android.content.res.XmlResourceParser;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.ViewAsserts;
 import android.util.LayoutDirection;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.RelativeLayout;
+import android.widget.cts.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
 
 /**
  * Test {@link RelativeLayout.LayoutParams}.
  */
 public class RelativeLayout_LayoutParamsTest extends
         ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
+    private Activity mActivity;
 
     public RelativeLayout_LayoutParamsTest() {
         super("android.widget.cts", RelativeLayoutCtsActivity.class);
     }
 
-    public void testConstructor() {
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+    }
+
+    public void testConstructor() throws XmlPullParserException, IOException {
 
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
         assertEquals(200, layoutParams.width);
@@ -46,22 +60,32 @@
         assertEquals(200, layoutParams.width);
         assertEquals(300, layoutParams.height);
 
+        ViewGroup.LayoutParams tempViewGroupLayoutParams = new ViewGroup.LayoutParams(300, 400);
+        layoutParams = new RelativeLayout.LayoutParams(tempViewGroupLayoutParams);
+        assertEquals(300, layoutParams.width);
+        assertEquals(400, layoutParams.height);
+
         MarginLayoutParams tempMarginLayoutParams = new MarginLayoutParams(400, 500);
         layoutParams = new RelativeLayout.LayoutParams(tempMarginLayoutParams);
         assertEquals(400, layoutParams.width);
         assertEquals(500, layoutParams.height);
 
+        XmlResourceParser p = mActivity.getResources().getLayout(R.layout.relative_layout);
+        XmlUtils.beginDocument(p, "RelativeLayout");
+        layoutParams = new RelativeLayout.LayoutParams(mActivity, p);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, layoutParams.width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, layoutParams.height);
+
         // Test RelativeLayout.Params which generated from the xml file.
         int rules[];
-        RelativeLayoutCtsActivity activity = getActivity();
 
         // test attributes used in RelativeLayout.
-        RelativeLayout relativeLayout = (RelativeLayout) activity.findViewById(
+        RelativeLayout relativeLayout = (RelativeLayout) mActivity.findViewById(
                 R.id.relative_sublayout_attrs);
 
         // view1, centered within its parent.
         // TEST: android:layout_centerInParent
-        View view1 = activity.findViewById(R.id.relative_view1);
+        View view1 = mActivity.findViewById(R.id.relative_view1);
         ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view1);
         ViewAsserts.assertVerticalCenterAligned(relativeLayout, view1);
         layoutParams = (RelativeLayout.LayoutParams) (view1.getLayoutParams());
@@ -70,7 +94,7 @@
 
         // view2, below view1 and has same left position with view1.
         // TEST: android:layout_below; android:layout_alignLeft
-        View view2 = activity.findViewById(R.id.relative_view2);
+        View view2 = mActivity.findViewById(R.id.relative_view2);
         ViewAsserts.assertLeftAligned(view1, view2);
         assertEquals(view1.getBottom(), view2.getTop());
         layoutParams = (RelativeLayout.LayoutParams) (view2.getLayoutParams());
@@ -81,7 +105,7 @@
         // view3, has same top position with view1 and same bottom position with view2,
         // and on the right of view1.1.
         // TEST: android:layout_alignTop; android:layout_alignBottom; android:layout_toRightOf
-        View view3 = activity.findViewById(R.id.relative_view3);
+        View view3 = mActivity.findViewById(R.id.relative_view3);
         ViewAsserts.assertTopAligned(view1, view3);
         ViewAsserts.assertBottomAligned(view2, view3);
         assertEquals(view1.getRight(), view3.getLeft());
@@ -93,7 +117,7 @@
 
         // view4, has same right position with view3 and above view3.
         // TEST: android:layout_alignRight; android:layout_above
-        View view4 = activity.findViewById(R.id.relative_view4);
+        View view4 = mActivity.findViewById(R.id.relative_view4);
         ViewAsserts.assertRightAligned(view3, view4);
         assertEquals(view3.getTop(), view4.getBottom());
         layoutParams = (RelativeLayout.LayoutParams) (view4.getLayoutParams());
@@ -103,7 +127,7 @@
 
         // view5 goes on the left-bottom.
         // TEST: android:layout_alignParentBottom; android:layout_alignParentLeft
-        View view5 = activity.findViewById(R.id.relative_view5);
+        View view5 = mActivity.findViewById(R.id.relative_view5);
         ViewAsserts.assertLeftAligned(relativeLayout, view5);
         ViewAsserts.assertBottomAligned(relativeLayout, view5);
         layoutParams = (RelativeLayout.LayoutParams) (view5.getLayoutParams());
@@ -113,7 +137,7 @@
 
         // view6 goes on the top-right.
         // TEST: android:layout_alignParentTop; android:layout_alignParentRight
-        View view6 = activity.findViewById(R.id.relative_view6);
+        View view6 = mActivity.findViewById(R.id.relative_view6);
         ViewAsserts.assertTopAligned(relativeLayout, view6);
         ViewAsserts.assertRightAligned(relativeLayout, view6);
         layoutParams = (RelativeLayout.LayoutParams) (view6.getLayoutParams());
@@ -123,7 +147,7 @@
 
         // view7, has same baseline with view6 and centered horizontally within its parent.
         // TEST: android:layout_alignBaseline; android:layout_centerHorizontal
-        View view7 = activity.findViewById(R.id.relative_view7);
+        View view7 = mActivity.findViewById(R.id.relative_view7);
         ViewAsserts.assertBaselineAligned(view6, view7);
         ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view7);
         layoutParams = (RelativeLayout.LayoutParams) (view7.getLayoutParams());
@@ -133,7 +157,7 @@
 
         // view8, centered vertically within its parent and on the left of view1.
         // TEST: android:layout_toLeftOf; android:layout_centerVertical
-        View view8 = activity.findViewById(R.id.relative_view8);
+        View view8 = mActivity.findViewById(R.id.relative_view8);
         ViewAsserts.assertVerticalCenterAligned(relativeLayout, view8);
         assertEquals(view1.getLeft(), view8.getRight());
         layoutParams = (RelativeLayout.LayoutParams) (view8.getLayoutParams());
@@ -144,7 +168,7 @@
         // view9, has same top and bottom position with view3 and same left position with its parent
         // TEST: android:layout_alignLeft; android:layout_alignTop; android:layout_alignBottom;
         // android:layout_alignWithParentIfMissing
-        View view9 = activity.findViewById(R.id.relative_view9);
+        View view9 = mActivity.findViewById(R.id.relative_view9);
         ViewAsserts.assertTopAligned(view3, view9);
         ViewAsserts.assertBottomAligned(view3, view9);
         ViewAsserts.assertLeftAligned(relativeLayout, view9);
@@ -160,15 +184,14 @@
 
         // Test RelativeLayout.Params which generated from the xml file.
         int rules[];
-        RelativeLayoutCtsActivity activity = getActivity();
 
         // test attributes used in RelativeLayout.
-        RelativeLayout relativeLayout = (RelativeLayout) activity.findViewById(
+        RelativeLayout relativeLayout = (RelativeLayout) mActivity.findViewById(
                 R.id.relative_sublayout_attrs_2);
 
         // view1, centered within its parent.
         // TEST: android:layout_centerInParent
-        View view1 = activity.findViewById(R.id.relative_view21);
+        View view1 = mActivity.findViewById(R.id.relative_view21);
         ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view1);
         ViewAsserts.assertVerticalCenterAligned(relativeLayout, view1);
         layoutParams = (RelativeLayout.LayoutParams) (view1.getLayoutParams());
@@ -177,7 +200,7 @@
 
         // view2, below view1 and has same left position with view1.
         // TEST: android:layout_below; android:layout_alignStart
-        View view2 = activity.findViewById(R.id.relative_view22);
+        View view2 = mActivity.findViewById(R.id.relative_view22);
         ViewAsserts.assertLeftAligned(view1, view2);
         assertEquals(view1.getBottom(), view2.getTop());
         layoutParams = (RelativeLayout.LayoutParams) (view2.getLayoutParams());
@@ -197,7 +220,7 @@
         // view3, has same top position with view1 and same bottom position with view2,
         // and on the right of view1.1.
         // TEST: android:layout_alignTop; android:layout_alignBottom; android:layout_toEndOf
-        View view3 = activity.findViewById(R.id.relative_view23);
+        View view3 = mActivity.findViewById(R.id.relative_view23);
         ViewAsserts.assertTopAligned(view1, view3);
         ViewAsserts.assertBottomAligned(view2, view3);
         assertEquals(view1.getRight(), view3.getLeft());
@@ -219,7 +242,7 @@
 
         // view4, has same right position with view3 and above view3.
         // TEST: android:layout_alignEnd; android:layout_above
-        View view4 = activity.findViewById(R.id.relative_view24);
+        View view4 = mActivity.findViewById(R.id.relative_view24);
         ViewAsserts.assertRightAligned(view3, view4);
         assertEquals(view3.getTop(), view4.getBottom());
         layoutParams = (RelativeLayout.LayoutParams) (view4.getLayoutParams());
@@ -238,7 +261,7 @@
 
         // view5 goes on the left-bottom.
         // TEST: android:layout_alignParentBottom; android:layout_alignParentStart
-        View view5 = activity.findViewById(R.id.relative_view25);
+        View view5 = mActivity.findViewById(R.id.relative_view25);
         ViewAsserts.assertLeftAligned(relativeLayout, view5);
         ViewAsserts.assertBottomAligned(relativeLayout, view5);
         layoutParams = (RelativeLayout.LayoutParams) (view5.getLayoutParams());
@@ -257,7 +280,7 @@
 
         // view6 goes on the top-right.
         // TEST: android:layout_alignParentTop; android:layout_alignParentEnd
-        View view6 = activity.findViewById(R.id.relative_view26);
+        View view6 = mActivity.findViewById(R.id.relative_view26);
         ViewAsserts.assertTopAligned(relativeLayout, view6);
         ViewAsserts.assertRightAligned(relativeLayout, view6);
         layoutParams = (RelativeLayout.LayoutParams) (view6.getLayoutParams());
@@ -276,7 +299,7 @@
 
         // view7, has same baseline with view6 and centered horizontally within its parent.
         // TEST: android:layout_alignBaseline; android:layout_centerHorizontal
-        View view7 = activity.findViewById(R.id.relative_view27);
+        View view7 = mActivity.findViewById(R.id.relative_view27);
         ViewAsserts.assertBaselineAligned(view6, view7);
         ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view7);
         layoutParams = (RelativeLayout.LayoutParams) (view7.getLayoutParams());
@@ -291,7 +314,7 @@
 
         // view8, centered vertically within its parent and on the left of view1.
         // TEST: android:layout_toStartOf; android:layout_centerVertical
-        View view8 = activity.findViewById(R.id.relative_view28);
+        View view8 = mActivity.findViewById(R.id.relative_view28);
         ViewAsserts.assertVerticalCenterAligned(relativeLayout, view8);
         assertEquals(view1.getLeft(), view8.getRight());
         layoutParams = (RelativeLayout.LayoutParams) (view8.getLayoutParams());
@@ -311,7 +334,7 @@
         // view9, has same top and bottom position with view3 and same left position with its parent
         // TEST: android:layout_alignStart; android:layout_alignTop; android:layout_alignBottom;
         // android:layout_alignWithParentIfMissing
-        View view9 = activity.findViewById(R.id.relative_view29);
+        View view9 = mActivity.findViewById(R.id.relative_view29);
         ViewAsserts.assertTopAligned(view3, view9);
         ViewAsserts.assertBottomAligned(view3, view9);
         ViewAsserts.assertLeftAligned(relativeLayout, view9);
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
index 369d7aa..2174c06 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
@@ -25,7 +25,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.RemoteViews;
-
 import android.widget.cts.R;
 
 public class RemoteViewsActivityTest
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsCtsActivity.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsCtsActivity.java
index 64001dc..364f522 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsCtsActivity.java
@@ -16,10 +16,7 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
-import android.cts.util.NullWebViewUtils;
 import android.os.Bundle;
 import android.widget.RemoteViews;
 
@@ -29,11 +26,7 @@
 public class RemoteViewsCtsActivity extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        try {
-            super.onCreate(savedInstanceState);
-            setContentView(R.layout.remoteviews_host);
-        } catch (Exception e) {
-            NullWebViewUtils.determineIfWebViewAvailable(this, e);
-        }
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.remoteviews_host);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index 605dbb6..0efc007 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -16,38 +16,64 @@
 
 package android.widget.cts;
 
-import android.graphics.drawable.Icon;
-import android.test.UiThreadTest;
-import android.widget.cts.R;
-
+import static org.junit.Assert.*;
 
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.app.PendingIntent;
 import android.app.Instrumentation.ActivityMonitor;
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.ColorStateList;
 import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Parcel;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.TextUtils;
+import android.util.TypedValue;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.AbsoluteLayout;
+import android.widget.AnalogClock;
+import android.widget.Button;
 import android.widget.Chronometer;
+import android.widget.DatePicker;
+import android.widget.DateTimeView;
 import android.widget.EditText;
 import android.widget.FrameLayout;
+import android.widget.GridLayout;
 import android.widget.GridView;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
+import android.widget.NumberPicker;
 import android.widget.ProgressBar;
+import android.widget.RatingBar;
 import android.widget.RelativeLayout;
 import android.widget.RemoteViews;
-import android.widget.TextView;
 import android.widget.RemoteViews.ActionException;
+import android.widget.SeekBar;
+import android.widget.StackView;
+import android.widget.TextClock;
+import android.widget.TextView;
+import android.widget.ViewFlipper;
+import android.widget.cts.util.TestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -58,42 +84,59 @@
 /**
  * Test {@link RemoteViews}.
  */
-public class RemoteViewsTest extends ActivityInstrumentationTestCase2<RemoteViewsCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class RemoteViewsTest {
     private static final String PACKAGE_NAME = "android.widget.cts";
 
-    private static final int INVALD_ID = -1;
+    private static final int INVALID_ID = -1;
 
     private static final long TEST_TIMEOUT = 5000;
 
+    @Rule
+    public ActivityTestRule<RemoteViewsCtsActivity> mActivityRule
+            = new ActivityTestRule<>(RemoteViewsCtsActivity.class);
+
+    @Rule
+    public ExpectedException mExpectedException = ExpectedException.none();
+
+    private Instrumentation mInstrumentation;
+
+    private Context mContext;
+
     private RemoteViews mRemoteViews;
 
     private View mResult;
 
-    private Activity mActivity;
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
+        mInstrumentation.runOnMainSync(() -> {
+            mRemoteViews = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+            mResult = mRemoteViews.apply(mContext, null);
 
-    public RemoteViewsTest() {
-        super(PACKAGE_NAME, RemoteViewsCtsActivity.class);
-    }
+            // Add our host view to the activity behind this test. This is similar to how launchers
+            // add widgets to the on-screen UI.
+            ViewGroup root = (ViewGroup) mActivityRule.getActivity().findViewById
+                    (R.id.remoteView_host);
+            FrameLayout.MarginLayoutParams lp = new FrameLayout.MarginLayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT);
+            mResult.setLayoutParams(lp);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mRemoteViews = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
-                mResult = mRemoteViews.apply(mActivity, null);
-            }
+            root.addView(mResult);
         });
     }
 
+    @Test
     public void testConstructor() {
         new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
 
         new RemoteViews(Parcel.obtain());
     }
 
+    @Test
     public void testGetPackage() {
         assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
 
@@ -101,105 +144,130 @@
         assertNull(mRemoteViews.getPackage());
     }
 
+    @Test
     public void testGetLayoutId() {
         assertEquals(R.layout.remoteviews_good, mRemoteViews.getLayoutId());
 
         mRemoteViews = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
         assertEquals(R.layout.listview_layout, mRemoteViews.getLayoutId());
 
-        mRemoteViews = new RemoteViews(PACKAGE_NAME, INVALD_ID);
-        assertEquals(INVALD_ID, mRemoteViews.getLayoutId());
+        mRemoteViews = new RemoteViews(PACKAGE_NAME, INVALID_ID);
+        assertEquals(INVALID_ID, mRemoteViews.getLayoutId());
 
         mRemoteViews = new RemoteViews(PACKAGE_NAME, 0);
         assertEquals(0, mRemoteViews.getLayoutId());
     }
 
+    @Test
+    public void testSetContentDescription() {
+        View view = mResult.findViewById(R.id.remoteView_frame);
+
+        assertNull(view.getContentDescription());
+
+        CharSequence contentDescription = mContext.getString(R.string.remote_content_description);
+        mRemoteViews.setContentDescription(R.id.remoteView_frame, contentDescription);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertTrue(TextUtils.equals(contentDescription, view.getContentDescription()));
+    }
+
+    @Test
     public void testSetViewVisibility() {
         View view = mResult.findViewById(R.id.remoteView_chronometer);
         assertEquals(View.VISIBLE, view.getVisibility());
 
         mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.INVISIBLE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.INVISIBLE, view.getVisibility());
 
         mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.GONE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.GONE, view.getVisibility());
 
         mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.VISIBLE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.VISIBLE, view.getVisibility());
     }
 
+    @Test
     public void testSetTextViewText() {
         TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
         assertEquals("", textView.getText().toString());
 
         String expected = "This is content";
         mRemoteViews.setTextViewText(R.id.remoteView_text, expected);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(expected, textView.getText().toString());
 
         mRemoteViews.setTextViewText(R.id.remoteView_text, null);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals("", textView.getText().toString());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setTextViewText(R.id.remoteView_absolute, "");
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
+    public void testSetTextViewTextSize() {
+        TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
+
+        mRemoteViews.setTextViewTextSize(R.id.remoteView_text, TypedValue.COMPLEX_UNIT_SP, 18);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(mContext.getResources().getDisplayMetrics().scaledDensity * 18,
+                textView.getTextSize(), 0.001f);
+
+        mExpectedException.expect(Throwable.class);
+        mRemoteViews.setTextViewTextSize(R.id.remoteView_absolute, TypedValue.COMPLEX_UNIT_SP, 20);
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @Test
     public void testSetIcon() {
         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
         assertNull(image.getDrawable());
 
-        Icon iconBlack = Icon.createWithResource(mActivity, R.drawable.icon_black);
+        Icon iconBlack = Icon.createWithResource(mContext, R.drawable.icon_black);
         mRemoteViews.setIcon(R.id.remoteView_image, "setImageIcon", iconBlack);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertNotNull(image.getDrawable());
-        BitmapDrawable dBlack = (BitmapDrawable) mActivity.getDrawable(R.drawable.icon_black);
+        BitmapDrawable dBlack = (BitmapDrawable) mContext.getDrawable(R.drawable.icon_black);
         WidgetTestUtils.assertEquals(dBlack.getBitmap(),
                 ((BitmapDrawable) image.getDrawable()).getBitmap());
     }
 
+    @Test
     public void testSetImageViewIcon() {
         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
         assertNull(image.getDrawable());
 
-        Icon iconBlue = Icon.createWithResource(mActivity, R.drawable.icon_blue);
+        Icon iconBlue = Icon.createWithResource(mContext, R.drawable.icon_blue);
         mRemoteViews.setImageViewIcon(R.id.remoteView_image, iconBlue);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertNotNull(image.getDrawable());
-        BitmapDrawable dBlue = (BitmapDrawable) mActivity.getDrawable(R.drawable.icon_blue);
+        BitmapDrawable dBlue = (BitmapDrawable) mContext.getDrawable(R.drawable.icon_blue);
         WidgetTestUtils.assertEquals(dBlue.getBitmap(),
                 ((BitmapDrawable) image.getDrawable()).getBitmap());
 
     }
 
+    @Test
     public void testSetImageViewResource() {
         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
         assertNull(image.getDrawable());
 
         mRemoteViews.setImageViewResource(R.id.remoteView_image, R.drawable.testimage);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertNotNull(image.getDrawable());
-        BitmapDrawable d = (BitmapDrawable) mActivity.getDrawable(R.drawable.testimage);
+        BitmapDrawable d = (BitmapDrawable) mContext.getDrawable(R.drawable.testimage);
         WidgetTestUtils.assertEquals(d.getBitmap(),
                 ((BitmapDrawable) image.getDrawable()).getBitmap());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setImageViewResource(R.id.remoteView_absolute, R.drawable.testimage);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
     public void testSetImageViewUri() throws IOException {
         String path = getTestImagePath();
         File imageFile = new File(path);
@@ -212,11 +280,11 @@
             assertNull(image.getDrawable());
 
             mRemoteViews.setImageViewUri(R.id.remoteView_image, uri);
-            mRemoteViews.reapply(mActivity, mResult);
+            mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
 
             Bitmap imageViewBitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
             Bitmap expectedBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
-                    mActivity.getResources(), R.raw.testimage, imageViewBitmap.getConfig());
+                    mContext.getResources(), R.raw.testimage, imageViewBitmap.getConfig());
             WidgetTestUtils.assertEquals(expectedBitmap, imageViewBitmap);
         } finally {
             imageFile.delete();
@@ -227,9 +295,10 @@
      * Returns absolute file path of location where test image should be stored
      */
     private String getTestImagePath() {
-        return getInstrumentation().getTargetContext().getFilesDir() + "/test.jpg";
+        return mContext.getFilesDir() + "/test.jpg";
     }
 
+    @Test
     public void testSetChronometer() {
         long base1 = 50;
         long base2 = -50;
@@ -237,31 +306,45 @@
 
         mRemoteViews.setChronometer(R.id.remoteView_chronometer, base1, "HH:MM:SS",
                 false);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(base1, chronometer.getBase());
         assertEquals("HH:MM:SS", chronometer.getFormat());
 
         mRemoteViews.setChronometer(R.id.remoteView_chronometer, base2, "HH:MM:SS",
                 false);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(base2, chronometer.getBase());
         assertEquals("HH:MM:SS", chronometer.getFormat());
 
         mRemoteViews.setChronometer(R.id.remoteView_chronometer, base1, "invalid",
                 true);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(base1, chronometer.getBase());
         assertEquals("invalid", chronometer.getFormat());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setChronometer(R.id.remoteView_absolute, base1, "invalid", true);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
+    public void testSetChronometerCountDown() {
+        Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer);
+
+        mRemoteViews.setChronometerCountDown(R.id.remoteView_chronometer, true);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertTrue(chronometer.isCountDown());
+
+        mRemoteViews.setChronometerCountDown(R.id.remoteView_chronometer, false);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertFalse(chronometer.isCountDown());
+
+        mExpectedException.expect(ActionException.class);
+        mRemoteViews.setChronometerCountDown(R.id.remoteView_absolute, true);
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @Test
     public void testSetProgressBar() {
         ProgressBar progress = (ProgressBar) mResult.findViewById(R.id.remoteView_progress);
         assertEquals(100, progress.getMax());
@@ -270,27 +353,24 @@
         assertFalse(progress.isIndeterminate());
 
         mRemoteViews.setProgressBar(R.id.remoteView_progress, 80, 50, true);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         // make the bar indeterminate will not affect max and progress
         assertEquals(100, progress.getMax());
         assertEquals(0, progress.getProgress());
         assertTrue(progress.isIndeterminate());
 
         mRemoteViews.setProgressBar(R.id.remoteView_progress, 60, 50, false);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(60, progress.getMax());
         assertEquals(50, progress.getProgress());
         assertFalse(progress.isIndeterminate());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setProgressBar(R.id.remoteView_relative, 60, 50, false);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
     public void testApply() {
         assertNotNull(mResult);
         assertNotNull(mResult.findViewById(R.id.remoteViews_good));
@@ -304,44 +384,58 @@
         assertNotNull(mResult.findViewById(R.id.remoteView_text));
     }
 
+    @Test
     public void testReapply() {
-        TextView text = new TextView(mActivity);
         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
         assertNull(image.getDrawable());
 
         mRemoteViews.setImageViewResource(R.id.remoteView_image, R.drawable.testimage);
-        mRemoteViews.reapply(mActivity, image);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, image));
         assertNotNull(image.getDrawable());
-        BitmapDrawable d = (BitmapDrawable) mActivity
+        BitmapDrawable d = (BitmapDrawable) mContext
                 .getResources().getDrawable(R.drawable.testimage);
         WidgetTestUtils.assertEquals(d.getBitmap(),
                 ((BitmapDrawable) image.getDrawable()).getBitmap());
     }
 
+    @Test
     public void testOnLoadClass() {
         mRemoteViews = new RemoteViews(Parcel.obtain());
 
-        assertTrue(mRemoteViews.onLoadClass(RelativeLayout.class));
-        assertTrue(mRemoteViews.onLoadClass(FrameLayout.class));
         assertTrue(mRemoteViews.onLoadClass(AbsoluteLayout.class));
-        assertTrue(mRemoteViews.onLoadClass(LinearLayout.class));
-        assertTrue(mRemoteViews.onLoadClass(TextView.class));
-        assertTrue(mRemoteViews.onLoadClass(ImageView.class));
-        assertTrue(mRemoteViews.onLoadClass(ProgressBar.class));
+        assertTrue(mRemoteViews.onLoadClass(AnalogClock.class));
+        assertTrue(mRemoteViews.onLoadClass(Button.class));
         assertTrue(mRemoteViews.onLoadClass(Chronometer.class));
-        assertTrue(mRemoteViews.onLoadClass(ListView.class));
+        assertTrue(mRemoteViews.onLoadClass(DateTimeView.class));
+        assertTrue(mRemoteViews.onLoadClass(FrameLayout.class));
+        assertTrue(mRemoteViews.onLoadClass(GridLayout.class));
         assertTrue(mRemoteViews.onLoadClass(GridView.class));
+        assertTrue(mRemoteViews.onLoadClass(ImageButton.class));
+        assertTrue(mRemoteViews.onLoadClass(ImageView.class));
+        assertTrue(mRemoteViews.onLoadClass(LinearLayout.class));
+        assertTrue(mRemoteViews.onLoadClass(ListView.class));
+        assertTrue(mRemoteViews.onLoadClass(ProgressBar.class));
+        assertTrue(mRemoteViews.onLoadClass(RelativeLayout.class));
+        assertTrue(mRemoteViews.onLoadClass(StackView.class));
+        assertTrue(mRemoteViews.onLoadClass(TextClock.class));
+        assertTrue(mRemoteViews.onLoadClass(TextView.class));
+        assertTrue(mRemoteViews.onLoadClass(ViewFlipper.class));
 
         // those classes without annotation @RemoteView
         assertFalse(mRemoteViews.onLoadClass(EditText.class));
+        assertFalse(mRemoteViews.onLoadClass(DatePicker.class));
+        assertFalse(mRemoteViews.onLoadClass(NumberPicker.class));
+        assertFalse(mRemoteViews.onLoadClass(RatingBar.class));
+        assertFalse(mRemoteViews.onLoadClass(SeekBar.class));
     }
 
+    @Test
     public void testDescribeContents() {
         mRemoteViews = new RemoteViews(Parcel.obtain());
         mRemoteViews.describeContents();
     }
 
-    @UiThreadTest
+    @Test
     public void testWriteToParcel() {
         mRemoteViews.setTextViewText(R.id.remoteView_text, "This is content");
         mRemoteViews.setViewVisibility(R.id.remoteView_frame, View.GONE);
@@ -351,7 +445,7 @@
 
         // the package and layout are successfully written into parcel
         mRemoteViews = RemoteViews.CREATOR.createFromParcel(p);
-        View result = mRemoteViews.apply(mActivity, null);
+        View result = mRemoteViews.apply(mContext, null);
         assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
         assertEquals(R.layout.remoteviews_good, mRemoteViews.getLayoutId());
         assertEquals("This is content", ((TextView) result.findViewById(R.id.remoteView_text))
@@ -359,12 +453,6 @@
         assertEquals(View.GONE, result.findViewById(R.id.remoteView_frame).getVisibility());
 
         p = Parcel.obtain();
-        try {
-            mRemoteViews.writeToParcel(null, 0);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-            // expected
-        }
 
         // currently the flag is not used
         mRemoteViews.writeToParcel(p, -1);
@@ -374,130 +462,120 @@
         RemoteViews[] remote = RemoteViews.CREATOR.newArray(1);
         assertNotNull(remote);
         assertEquals(1, remote.length);
-
-        try {
-            RemoteViews.CREATOR.newArray(-1);
-            fail("should throw NegativeArraySizeException");
-        } catch (NegativeArraySizeException e) {
-            // expected
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testWriteNullToParcel() {
+        mRemoteViews.writeToParcel(null, 0);
+    }
+
+    @Test(expected=NegativeArraySizeException.class)
+    public void testCreateNegativeSizedArray() {
+        RemoteViews.CREATOR.newArray(-1);
+    }
+
+    @Test
     public void testSetImageViewBitmap() {
         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
         assertNull(image.getDrawable());
 
         Bitmap bitmap =
-                BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.testimage);
+                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage);
         mRemoteViews.setImageViewBitmap(R.id.remoteView_image, bitmap);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertNotNull(image.getDrawable());
         WidgetTestUtils.assertEquals(bitmap, ((BitmapDrawable) image.getDrawable()).getBitmap());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setImageViewBitmap(R.id.remoteView_absolute, bitmap);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
     public void testSetBitmap() {
         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
         assertNull(image.getDrawable());
 
         Bitmap bitmap =
-                BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.testimage);
+                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage);
         mRemoteViews.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertNotNull(image.getDrawable());
         WidgetTestUtils.assertEquals(bitmap, ((BitmapDrawable) image.getDrawable()).getBitmap());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setBitmap(R.id.remoteView_absolute, "setImageBitmap", bitmap);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
     public void testSetBoolean() {
         ProgressBar progress = (ProgressBar) mResult.findViewById(R.id.remoteView_progress);
         // the view uses style progressBarHorizontal, so the default is false
         assertFalse(progress.isIndeterminate());
 
         mRemoteViews.setBoolean(R.id.remoteView_progress, "setIndeterminate", true);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertTrue(progress.isIndeterminate());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setBoolean(R.id.remoteView_relative, "setIndeterminate", false);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
     public void testSetCharSequence() {
         TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
         assertEquals("", textView.getText().toString());
 
         String expected = "test setCharSequence";
         mRemoteViews.setCharSequence(R.id.remoteView_text, "setText", expected);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(expected, textView.getText().toString());
 
         mRemoteViews.setCharSequence(R.id.remoteView_text, "setText", null);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals("", textView.getText().toString());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setCharSequence(R.id.remoteView_absolute, "setText", "");
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
     public void testSetInt() {
         View view = mResult.findViewById(R.id.remoteView_chronometer);
         assertEquals(View.VISIBLE, view.getVisibility());
 
         mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.INVISIBLE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.INVISIBLE, view.getVisibility());
 
         mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.GONE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.GONE, view.getVisibility());
 
         mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.VISIBLE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.VISIBLE, view.getVisibility());
     }
 
+    @Test
     public void testSetString() {
         String format = "HH:MM:SS";
         Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer);
         assertNull(chronometer.getFormat());
 
         mRemoteViews.setString(R.id.remoteView_chronometer, "setFormat", format);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(format, chronometer.getFormat());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setString(R.id.remoteView_image, "setFormat", format);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
     public void testSetUri() throws IOException {
         String path = getTestImagePath();
         File imagefile = new File(path);
@@ -510,50 +588,102 @@
             assertNull(image.getDrawable());
 
             mRemoteViews.setUri(R.id.remoteView_image, "setImageURI", uri);
-            mRemoteViews.reapply(mActivity, mResult);
+            mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
 
             Bitmap imageViewBitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
             Bitmap expectedBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
-                    mActivity.getResources(), R.raw.testimage, imageViewBitmap.getConfig());
+                    mContext.getResources(), R.raw.testimage, imageViewBitmap.getConfig());
             WidgetTestUtils.assertEquals(expectedBitmap, imageViewBitmap);
 
+            mExpectedException.expect(ActionException.class);
             mRemoteViews.setUri(R.id.remoteView_absolute, "setImageURI", uri);
-            try {
-                mRemoteViews.reapply(mActivity, mResult);
-                fail("Should throw ActionException");
-            } catch (ActionException e) {
-                // expected
-            }
+            mRemoteViews.reapply(mContext, mResult);
         } finally {
             // remove the test image file
             imagefile.delete();
         }
     }
 
+    @Test
     public void testSetTextColor() {
         TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
 
         mRemoteViews.setTextColor(R.id.remoteView_text, R.color.testcolor1);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertSame(ColorStateList.valueOf(R.color.testcolor1), textView.getTextColors());
 
         mRemoteViews.setTextColor(R.id.remoteView_text, R.color.testcolor2);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertSame(ColorStateList.valueOf(R.color.testcolor2), textView.getTextColors());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setTextColor(R.id.remoteView_absolute, R.color.testcolor1);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
+    public void testSetTextCompoundDrawables() {
+        TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
+
+        TestUtils.verifyCompoundDrawables(textView, -1, -1, -1, -1);
+
+        mRemoteViews.setTextViewCompoundDrawables(R.id.remoteView_text, R.drawable.start,
+                R.drawable.pass, R.drawable.failed, 0);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        TestUtils.verifyCompoundDrawables(textView, R.drawable.start, R.drawable.failed,
+                R.drawable.pass, -1);
+
+        mRemoteViews.setTextViewCompoundDrawables(R.id.remoteView_text, 0,
+                R.drawable.icon_black, R.drawable.icon_red, R.drawable.icon_green);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        TestUtils.verifyCompoundDrawables(textView, -1,  R.drawable.icon_red, R.drawable.icon_black,
+                R.drawable.icon_green);
+
+        mExpectedException.expect(Throwable.class);
+        mRemoteViews.setTextViewCompoundDrawables(R.id.remoteView_absolute, 0,
+                R.drawable.start, R.drawable.failed, 0);
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @Test
+    public void testSetTextCompoundDrawablesRelative() {
+        TextView textViewLtr = (TextView) mResult.findViewById(R.id.remoteView_text_ltr);
+        TextView textViewRtl = (TextView) mResult.findViewById(R.id.remoteView_text_rtl);
+
+        TestUtils.verifyCompoundDrawables(textViewLtr, -1, -1, -1, -1);
+        TestUtils.verifyCompoundDrawables(textViewRtl, -1, -1, -1, -1);
+
+        mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_ltr,
+                R.drawable.start, R.drawable.pass, R.drawable.failed, 0);
+        mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_rtl,
+                R.drawable.start, R.drawable.pass, R.drawable.failed, 0);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        TestUtils.verifyCompoundDrawables(textViewLtr, R.drawable.start, R.drawable.failed,
+                R.drawable.pass, -1);
+        TestUtils.verifyCompoundDrawables(textViewRtl, R.drawable.failed, R.drawable.start,
+                R.drawable.pass, -1);
+
+        mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_ltr, 0,
+                R.drawable.icon_black, R.drawable.icon_red, R.drawable.icon_green);
+        mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_rtl, 0,
+                R.drawable.icon_black, R.drawable.icon_red, R.drawable.icon_green);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        TestUtils.verifyCompoundDrawables(textViewLtr, -1, R.drawable.icon_red,
+                R.drawable.icon_black, R.drawable.icon_green);
+        TestUtils.verifyCompoundDrawables(textViewRtl, R.drawable.icon_red, -1,
+                R.drawable.icon_black, R.drawable.icon_green);
+
+        mExpectedException.expect(Throwable.class);
+        mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_absolute, 0,
+                R.drawable.start, R.drawable.failed, 0);
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @LargeTest
+    @Test
     public void testSetOnClickPendingIntent() {
         Uri uri = Uri.parse("ctstest://RemoteView/test");
-        Instrumentation instrumentation = getInstrumentation();
-        ActivityMonitor am = instrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
+        ActivityMonitor am = mInstrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
                 null, false);
         View view = mResult.findViewById(R.id.remoteView_image);
         view.performClick();
@@ -561,81 +691,237 @@
         assertNull(newActivity);
 
         Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-        PendingIntent pendingIntent = PendingIntent.getActivity(mActivity, 0, intent, 0);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
         mRemoteViews.setOnClickPendingIntent(R.id.remoteView_image, pendingIntent);
-        mRemoteViews.reapply(mActivity, mResult);
-        view.performClick();
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        mInstrumentation.runOnMainSync(() -> view.performClick());
         newActivity = am.waitForActivityWithTimeout(TEST_TIMEOUT);
         assertNotNull(newActivity);
+        assertTrue(newActivity instanceof MockURLSpanTestActivity);
         newActivity.finish();
     }
 
+    @Test
     public void testSetLong() {
         long base1 = 50;
         long base2 = -50;
         Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer);
 
         mRemoteViews.setLong(R.id.remoteView_chronometer, "setBase", base1);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(base1, chronometer.getBase());
 
         mRemoteViews.setLong(R.id.remoteView_chronometer, "setBase", base2);
-        mRemoteViews.reapply(mActivity, mResult);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(base2, chronometer.getBase());
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setLong(R.id.remoteView_absolute, "setBase", base1);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
+    @Test
     public void testSetFloat() {
         LinearLayout linearLayout = (LinearLayout) mResult.findViewById(R.id.remoteView_linear);
         assertTrue(linearLayout.getWeightSum() <= 0.0f);
 
         mRemoteViews.setFloat(R.id.remoteView_linear, "setWeightSum", 0.5f);
-        mRemoteViews.reapply(mActivity, mResult);
-        assertEquals(0.5f, linearLayout.getWeightSum());
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(0.5f, linearLayout.getWeightSum(), 0.001f);
 
+        mExpectedException.expect(ActionException.class);
         mRemoteViews.setFloat(R.id.remoteView_absolute, "setWeightSum", 1.0f);
-        try {
-            mRemoteViews.reapply(mActivity, mResult);
-            fail("Should throw ActionException");
-        } catch (ActionException e) {
-            // expected
-        }
+        mRemoteViews.reapply(mContext, mResult);
     }
 
-    public void testNotFeasibleSetters() {
-        // there is no RemotableViewMethods to use them, how to test?
+    @Test
+    public void testSetByte() {
+        MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
+        assertEquals(0, customView.getByteField());
+
+        byte b = 100;
+        mRemoteViews.setByte(R.id.remoteView_custom, "setByteField", b);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(b, customView.getByteField());
+
+        mExpectedException.expect(ActionException.class);
+        mRemoteViews.setByte(R.id.remoteView_absolute, "setByteField", b);
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @Test
+    public void testSetChar() {
+        MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
+        assertEquals('\u0000', customView.getCharField());
+
+        mRemoteViews.setChar(R.id.remoteView_custom, "setCharField", 'q');
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals('q', customView.getCharField());
+
+        mExpectedException.expect(ActionException.class);
+        mRemoteViews.setChar(R.id.remoteView_absolute, "setCharField", 'w');
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @Test
+    public void testSetDouble() {
+        MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
+        assertEquals(0.0, customView.getDoubleField(), 0.0f);
+
+        mRemoteViews.setDouble(R.id.remoteView_custom, "setDoubleField", 0.5);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(0.5, customView.getDoubleField(), 0.001f);
+
+        mExpectedException.expect(ActionException.class);
+        mRemoteViews.setDouble(R.id.remoteView_absolute, "setDoubleField", 1.0);
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @Test
+    public void testSetShort() {
+        MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
+        assertEquals(0, customView.getShortField());
+
+        short s = 25;
+        mRemoteViews.setShort(R.id.remoteView_custom, "setShortField", s);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(s, customView.getShortField());
+
+        mExpectedException.expect(ActionException.class);
+        mRemoteViews.setShort(R.id.remoteView_absolute, "setShortField", s);
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @Test
+    public void testSetBundle() {
+        MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
+        assertNull(customView.getBundleField());
+
+        final Bundle bundle = new Bundle();
+        bundle.putString("STR", "brexit");
+        bundle.putInt("INT", 2016);
+        mRemoteViews.setBundle(R.id.remoteView_custom, "setBundleField", bundle);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        final Bundle fromRemote = customView.getBundleField();
+        assertEquals("brexit", fromRemote.getString("STR", ""));
+        assertEquals(2016, fromRemote.getInt("INT", 0));
+
+        mExpectedException.expect(ActionException.class);
+        mRemoteViews.setBundle(R.id.remoteView_absolute, "setBundleField", bundle);
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @Test
+    public void testSetIntent() {
+        MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
+        assertNull(customView.getIntentField());
+
+        final Intent intent = new Intent(mContext, SwitchCtsActivity.class);
+        intent.putExtra("STR", "brexit");
+        intent.putExtra("INT", 2016);
+        mRemoteViews.setIntent(R.id.remoteView_custom, "setIntentField", intent);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        final Intent fromRemote = customView.getIntentField();
+        assertEquals(SwitchCtsActivity.class.getName(), fromRemote.getComponent().getClassName());
+        assertEquals("brexit", fromRemote.getStringExtra("STR"));
+        assertEquals(2016, fromRemote.getIntExtra("INT", 0));
+
+        mExpectedException.expect(ActionException.class);
+        mRemoteViews.setIntent(R.id.remoteView_absolute, "setIntentField", intent);
+        mRemoteViews.reapply(mContext, mResult);
+    }
+
+    @Test
+    public void testRemoveAllViews() {
+        ViewGroup root = (ViewGroup) mResult.findViewById(R.id.remoteViews_good);
+        assertTrue(root.getChildCount() > 0);
+
+        mRemoteViews.removeAllViews(R.id.remoteViews_good);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(0, root.getChildCount());
+    }
+
+    @Test
+    public void testAddView() {
+        ViewGroup root = (ViewGroup) mResult.findViewById(R.id.remoteViews_good);
+        int originalChildCount = root.getChildCount();
+
+        assertNull(root.findViewById(R.id.remoteView_frame_extra));
+
+        // Create a RemoteViews wrapper around a layout and add it to our root
+        RemoteViews extra = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_extra);
+        mRemoteViews.addView(R.id.remoteViews_good, extra);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+
+        // Verify that our root has that layout as its last (new) child
+        assertEquals(originalChildCount + 1, root.getChildCount());
+        assertNotNull(root.findViewById(R.id.remoteView_frame_extra));
+        assertEquals(R.id.remoteView_frame_extra, root.getChildAt(originalChildCount).getId());
+    }
+
+    @Test
+    public void testSetLabelFor() {
+        View labelView = mResult.findViewById(R.id.remoteView_label);
+        assertEquals(View.NO_ID, labelView.getLabelFor());
+
+        mRemoteViews.setLabelFor(R.id.remoteView_label, R.id.remoteView_text);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_text, labelView.getLabelFor());
+    }
+
+    @Test
+    public void testSetAccessibilityTraversalAfter() {
+        View textView = mResult.findViewById(R.id.remoteView_text);
+
+        mRemoteViews.setAccessibilityTraversalAfter(R.id.remoteView_text, R.id.remoteView_frame);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_frame, textView.getAccessibilityTraversalAfter());
+
+        mRemoteViews.setAccessibilityTraversalAfter(R.id.remoteView_text, R.id.remoteView_linear);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_linear, textView.getAccessibilityTraversalAfter());
+    }
+
+    @Test
+    public void testSetAccessibilityTraversalBefore() {
+        View textView = mResult.findViewById(R.id.remoteView_text);
+
+        mRemoteViews.setAccessibilityTraversalBefore(R.id.remoteView_text, R.id.remoteView_frame);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_frame, textView.getAccessibilityTraversalBefore());
+
+        mRemoteViews.setAccessibilityTraversalBefore(R.id.remoteView_text, R.id.remoteView_linear);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_linear, textView.getAccessibilityTraversalBefore());
+    }
+
+    @Test
+    public void testSetViewPadding() {
+        View textView = mResult.findViewById(R.id.remoteView_text);
+
+        mRemoteViews.setViewPadding(R.id.remoteView_text, 10, 20, 30, 40);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(10, textView.getPaddingLeft());
+        assertEquals(20, textView.getPaddingTop());
+        assertEquals(30, textView.getPaddingRight());
+        assertEquals(40, textView.getPaddingBottom());
+
+        mRemoteViews.setViewPadding(R.id.remoteView_text, 40, 30, 20, 10);
+        mInstrumentation.runOnMainSync(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(40, textView.getPaddingLeft());
+        assertEquals(30, textView.getPaddingTop());
+        assertEquals(20, textView.getPaddingRight());
+        assertEquals(10, textView.getPaddingBottom());
     }
 
     private void createSampleImage(File imagefile, int resid) throws IOException {
-        InputStream source = null;
-        OutputStream target = null;
-
-        try {
-            source = mActivity.getResources().openRawResource(resid);
-            target = new FileOutputStream(imagefile);
+        try (InputStream source = mContext.getResources().openRawResource(resid);
+             OutputStream target = new FileOutputStream(imagefile)) {
 
             byte[] buffer = new byte[1024];
             for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
                 target.write(buffer, 0, len);
             }
-        } finally {
-            try {
-                if (source != null) {
-                    source.close();
-                }
-                if (target != null) {
-                    target.close();
-                }
-            } catch (IOException ignored) {
-                // Ignore the IOException.
-            }
         }
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsWidgetTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsWidgetTest.java
new file mode 100644
index 0000000..e1a77dc
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsWidgetTest.java
@@ -0,0 +1,512 @@
+/*
+ * 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.widget.cts;
+
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.cts.util.PollingCheck;
+import android.cts.util.SystemUtil;
+import android.os.Bundle;
+import android.os.Process;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.FrameLayout;
+import android.widget.ListView;
+import android.widget.RemoteViews;
+import android.widget.RemoteViewsService;
+import android.widget.StackView;
+import android.widget.cts.appwidget.MyAppWidgetProvider;
+import android.widget.cts.appwidget.MyAppWidgetService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Test {@link RemoteViews} that expect to operate within a {@link AppWidgetHostView} root.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class RemoteViewsWidgetTest {
+    public static final String[] COUNTRY_LIST = new String[] {
+        "Argentina", "Australia", "Belize", "Botswana", "Brazil", "Cameroon", "China", "Cyprus",
+        "Denmark", "Djibouti", "Ethiopia", "Fiji", "Finland", "France", "Gabon", "Germany",
+        "Ghana", "Haiti", "Honduras", "Iceland", "India", "Indonesia", "Ireland", "Italy",
+        "Japan", "Kiribati", "Laos", "Lesotho", "Liberia", "Malaysia", "Mongolia", "Myanmar",
+        "Nauru", "Norway", "Oman", "Pakistan", "Philippines", "Portugal", "Romania", "Russia",
+        "Rwanda", "Singapore", "Slovakia", "Slovenia", "Somalia", "Swaziland", "Togo", "Tuvalu",
+        "Uganda", "Ukraine", "United States", "Vanuatu", "Venezuela", "Zimbabwe"
+    };
+
+    private static final String GRANT_BIND_APP_WIDGET_PERMISSION_COMMAND =
+        "appwidget grantbind --package android.widget.cts --user 0";
+
+    private static final String REVOKE_BIND_APP_WIDGET_PERMISSION_COMMAND =
+        "appwidget revokebind --package android.widget.cts --user 0";
+
+    private static final long TEST_TIMEOUT_MS = 5000;
+
+    @Rule
+    public ActivityTestRule<RemoteViewsCtsActivity> mActivityRule
+            = new ActivityTestRule<>(RemoteViewsCtsActivity.class);
+
+    private Instrumentation mInstrumentation;
+
+    private Context mContext;
+
+    private boolean mHasAppWidgets;
+
+    private AppWidgetHostView mAppWidgetHostView;
+
+    private int mAppWidgetId;
+
+    private StackView mStackView;
+
+    private ListView mListView;
+
+    private AppWidgetHost mAppWidgetHost;
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
+
+        mHasAppWidgets = hasAppWidgets();
+        if (!mHasAppWidgets) {
+            return;
+        }
+
+        // We want to bind widgets - run a shell command to grant bind permission to our
+        // package.
+        grantBindAppWidgetPermission();
+
+        mAppWidgetHost = new AppWidgetHost(mContext, 0);
+
+        mAppWidgetHost.deleteHost();
+        mAppWidgetHost.startListening();
+
+        // Configure the app widget provider behavior
+        final CountDownLatch providerCountDownLatch = new CountDownLatch(2);
+        MyAppWidgetProvider.configure(providerCountDownLatch, null, null);
+
+        // Grab the provider to be bound
+        final AppWidgetProviderInfo providerInfo = getAppWidgetProviderInfo();
+
+        // Allocate a widget id to bind
+        mAppWidgetId = mAppWidgetHost.allocateAppWidgetId();
+
+        // Bind the app widget
+        boolean isBinding = getAppWidgetManager().bindAppWidgetIdIfAllowed(mAppWidgetId,
+                providerInfo.getProfile(), providerInfo.provider, null);
+        assertTrue(isBinding);
+
+        // Wait for onEnabled and onUpdate calls on our provider
+        try {
+            assertTrue(providerCountDownLatch.await(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ie) {
+            fail(ie.getMessage());
+        }
+
+        // Configure the app widget service behavior
+        final CountDownLatch factoryCountDownLatch = new CountDownLatch(2);
+        RemoteViewsService.RemoteViewsFactory factory =
+                mock(RemoteViewsService.RemoteViewsFactory.class);
+        when(factory.getCount()).thenReturn(COUNTRY_LIST.length);
+        doAnswer(new Answer<RemoteViews>() {
+            @Override
+            public RemoteViews answer(InvocationOnMock invocation) throws Throwable {
+                final int position = (Integer) invocation.getArguments()[0];
+                RemoteViews remoteViews = new RemoteViews(mContext.getPackageName(),
+                        R.layout.remoteviews_adapter_item);
+                remoteViews.setTextViewText(R.id.item, COUNTRY_LIST[position]);
+
+                // Set a fill-intent which will be used to fill-in the pending intent template
+                // which is set on the collection view in MyAppWidgetProvider.
+                Bundle extras = new Bundle();
+                extras.putString(MockURLSpanTestActivity.KEY_PARAM, COUNTRY_LIST[position]);
+                Intent fillInIntent = new Intent();
+                fillInIntent.putExtras(extras);
+                remoteViews.setOnClickFillInIntent(R.id.item, fillInIntent);
+
+                if (position == 0) {
+                    factoryCountDownLatch.countDown();
+                }
+                return remoteViews;
+            }
+        }).when(factory).getViewAt(any(int.class));
+        when(factory.getViewTypeCount()).thenReturn(1);
+        MyAppWidgetService.setFactory(factory);
+
+        mInstrumentation.runOnMainSync(
+                () -> mAppWidgetHostView = mAppWidgetHost.createView(
+                        mContext, mAppWidgetId, providerInfo));
+
+        // Wait our factory to be called to create the first item
+        try {
+            assertTrue(factoryCountDownLatch.await(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ie) {
+            fail(ie.getMessage());
+        }
+
+        // Add our host view to the activity behind this test. This is similar to how launchers
+        // add widgets to the on-screen UI.
+        ViewGroup root = (ViewGroup) mActivityRule.getActivity().findViewById(R.id.remoteView_host);
+        FrameLayout.MarginLayoutParams lp = new FrameLayout.MarginLayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mAppWidgetHostView.setLayoutParams(lp);
+
+        mInstrumentation.runOnMainSync(() -> root.addView(mAppWidgetHostView));
+    }
+
+    @After
+    public void teardown() {
+        mAppWidgetHost.deleteHost();
+        revokeBindAppWidgetPermission();
+    }
+
+    private void grantBindAppWidgetPermission() {
+        try {
+            SystemUtil.runShellCommand(mInstrumentation, GRANT_BIND_APP_WIDGET_PERMISSION_COMMAND);
+        } catch (IOException e) {
+            fail("Error granting app widget permission. Command: "
+                    + GRANT_BIND_APP_WIDGET_PERMISSION_COMMAND + ": ["
+                    + e.getMessage() + "]");
+        }
+    }
+
+    private void revokeBindAppWidgetPermission() {
+        try {
+            SystemUtil.runShellCommand(mInstrumentation, REVOKE_BIND_APP_WIDGET_PERMISSION_COMMAND);
+        } catch (IOException e) {
+            fail("Error revoking app widget permission. Command: "
+                    + REVOKE_BIND_APP_WIDGET_PERMISSION_COMMAND + ": ["
+                    + e.getMessage() + "]");
+        }
+    }
+
+    private boolean hasAppWidgets() {
+        return mInstrumentation.getTargetContext().getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS);
+    }
+
+    private AppWidgetManager getAppWidgetManager() {
+        return (AppWidgetManager) mContext.getSystemService(Context.APPWIDGET_SERVICE);
+    }
+
+    private AppWidgetProviderInfo getAppWidgetProviderInfo() {
+        ComponentName firstComponentName = new ComponentName(mContext.getPackageName(),
+                MyAppWidgetProvider.class.getName());
+
+        return getProviderInfo(firstComponentName);
+    }
+
+    private AppWidgetProviderInfo getProviderInfo(ComponentName componentName) {
+        List<AppWidgetProviderInfo> providers = getAppWidgetManager().getInstalledProviders();
+
+        final int providerCount = providers.size();
+        for (int i = 0; i < providerCount; i++) {
+            AppWidgetProviderInfo provider = providers.get(i);
+            if (componentName.equals(provider.provider)
+                    && Process.myUserHandle().equals(provider.getProfile())) {
+                return provider;
+
+            }
+        }
+
+        return null;
+    }
+
+    @Test
+    public void testInitialState() {
+        if (!mHasAppWidgets) {
+            return;
+        }
+
+        assertNotNull(mAppWidgetHostView);
+        mStackView = (StackView) mAppWidgetHostView.findViewById(R.id.remoteViews_stack);
+        assertNotNull(mStackView);
+
+        assertEquals(COUNTRY_LIST.length, mStackView.getCount());
+        assertEquals(0, mStackView.getDisplayedChild());
+        assertEquals(R.id.remoteViews_empty, mStackView.getEmptyView().getId());
+    }
+
+    private void verifySetDisplayedChild(int displayedChildIndex) {
+        final CountDownLatch updateLatch = new CountDownLatch(1);
+        MyAppWidgetProvider.configure(updateLatch, null, null);
+
+        // Create the intent to update the widget. Note that we're passing the value
+        // for displayed child index in the intent
+        Intent intent = new Intent(mContext, MyAppWidgetProvider.class);
+        intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new  int[] { mAppWidgetId });
+        intent.putExtra(MyAppWidgetProvider.KEY_DISPLAYED_CHILD_INDEX, displayedChildIndex);
+        mContext.sendBroadcast(intent);
+
+        // Wait until the update request has been processed
+        try {
+            assertTrue(updateLatch.await(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ie) {
+            fail(ie.getMessage());
+        }
+        // And wait until the underlying StackView has been updated to switch to the requested
+        // child
+        PollingCheck.waitFor(TEST_TIMEOUT_MS,
+                () -> mStackView.getDisplayedChild() == displayedChildIndex);
+    }
+
+    @Test
+    public void testSetDisplayedChild() {
+        if (!mHasAppWidgets) {
+            return;
+        }
+
+        mStackView = (StackView) mAppWidgetHostView.findViewById(R.id.remoteViews_stack);
+
+        verifySetDisplayedChild(4);
+        verifySetDisplayedChild(2);
+        verifySetDisplayedChild(6);
+    }
+
+    private void verifyShowCommand(String intentShowKey, int expectedDisplayedChild) {
+        final CountDownLatch updateLatch = new CountDownLatch(1);
+        MyAppWidgetProvider.configure(updateLatch, null, null);
+
+        // Create the intent to update the widget. Note that we're passing the "indication"
+        // which one of showNext / showPrevious APIs to execute in the intent that we're
+        // creating.
+        Intent intent = new Intent(mContext, MyAppWidgetProvider.class);
+        intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new  int[] { mAppWidgetId });
+        intent.putExtra(intentShowKey, true);
+        mContext.sendBroadcast(intent);
+
+        // Wait until the update request has been processed
+        try {
+            assertTrue(updateLatch.await(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ie) {
+            fail(ie.getMessage());
+        }
+        // And wait until the underlying StackView has been updated to switch to the expected
+        // child
+        PollingCheck.waitFor(TEST_TIMEOUT_MS,
+                () -> mStackView.getDisplayedChild() == expectedDisplayedChild);
+    }
+
+    @Test
+    public void testShowNextPrevious() {
+        if (!mHasAppWidgets) {
+            return;
+        }
+
+        mStackView = (StackView) mAppWidgetHostView.findViewById(R.id.remoteViews_stack);
+
+        // Two forward
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_NEXT, 1);
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_NEXT, 2);
+        // Four back (looping to the end of the adapter data)
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_PREVIOUS, 1);
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_PREVIOUS, 0);
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_PREVIOUS, COUNTRY_LIST.length - 1);
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_PREVIOUS, COUNTRY_LIST.length - 2);
+        // And three forward (looping to the start of the adapter data)
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_NEXT, COUNTRY_LIST.length - 1);
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_NEXT, 0);
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_NEXT, 1);
+    }
+
+    private void verifyItemClickIntents(int indexToClick) {
+        Instrumentation.ActivityMonitor am = mInstrumentation.addMonitor(
+                MockURLSpanTestActivity.class.getName(), null, false);
+
+        mStackView = (StackView) mAppWidgetHostView.findViewById(R.id.remoteViews_stack);
+        PollingCheck.waitFor(() -> mStackView.getCurrentView() != null);
+        final View initialView = mStackView.getCurrentView();
+        mInstrumentation.runOnMainSync(
+                () -> mStackView.performItemClick(initialView, indexToClick, 0L));
+
+        Activity newActivity = am.waitForActivityWithTimeout(TEST_TIMEOUT_MS);
+        assertNotNull(newActivity);
+        assertTrue(newActivity instanceof MockURLSpanTestActivity);
+        assertEquals(COUNTRY_LIST[indexToClick], ((MockURLSpanTestActivity) newActivity).getParam());
+        newActivity.finish();
+    }
+
+    @Test
+    public void testSetOnClickPendingIntent() {
+        if (!mHasAppWidgets) {
+            return;
+        }
+
+        verifyItemClickIntents(0);
+
+        // Switch to another child
+        verifySetDisplayedChild(2);
+        verifyItemClickIntents(2);
+
+        // And one more
+        verifyShowCommand(MyAppWidgetProvider.KEY_SHOW_NEXT, 3);
+        verifyItemClickIntents(3);
+    }
+
+    private class ListScrollListener implements AbsListView.OnScrollListener {
+        private CountDownLatch mLatchToNotify;
+
+        private int mTargetPosition;
+
+        public ListScrollListener(CountDownLatch latchToNotify, int targetPosition) {
+            mLatchToNotify = latchToNotify;
+            mTargetPosition = targetPosition;
+        }
+
+        @Override
+        public void onScrollStateChanged(AbsListView view, int scrollState) {
+        }
+
+        @Override
+        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+                int totalItemCount) {
+            if ((mTargetPosition >= firstVisibleItem) &&
+                    (mTargetPosition <= (firstVisibleItem + visibleItemCount))) {
+                mLatchToNotify.countDown();
+            }
+        }
+    }
+
+    @Test
+    public void testSetScrollPosition() {
+        if (!mHasAppWidgets) {
+            return;
+        }
+
+        mListView = (ListView) mAppWidgetHostView.findViewById(R.id.remoteViews_list);
+
+        final CountDownLatch updateLatch = new CountDownLatch(1);
+        final AtomicBoolean scrollToPositionIsComplete = new AtomicBoolean(false);
+        // We're configuring our provider with three parameters:
+        // 1. The CountDownLatch to be notified when the provider has been enabled
+        // 2. The gating condition that waits until ListView has populated its content
+        //    so that we can proceed to call setScrollPosition on it
+        // 3. The gating condition that waits until the setScrollPosition has completed
+        //    its processing / scrolling so that we can proceed to call
+        //    setRelativeScrollPosition on it
+        MyAppWidgetProvider.configure(updateLatch, () -> mListView.getChildCount() > 0,
+                scrollToPositionIsComplete::get);
+
+        final int positionToScrollTo = COUNTRY_LIST.length - 10;
+        final int scrollByAmount = COUNTRY_LIST.length / 2;
+        final int offsetScrollTarget = positionToScrollTo - scrollByAmount;
+
+        // Register the first scroll listener on our ListView. The listener will notify our latch
+        // when the "target" item comes into view. If that never happens, the latch will
+        // time out and fail the test.
+        final CountDownLatch scrollToPositionLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(
+                new ListScrollListener(scrollToPositionLatch, positionToScrollTo));
+
+        // Create the intent to update the widget. Note that we're passing the "indication"
+        // to switch to our ListView in the intent that we're creating.
+        Intent intent = new Intent(mContext, MyAppWidgetProvider.class);
+        intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new  int[] { mAppWidgetId });
+        intent.putExtra(MyAppWidgetProvider.KEY_SWITCH_TO_LIST, true);
+        intent.putExtra(MyAppWidgetProvider.KEY_SCROLL_POSITION, positionToScrollTo);
+        intent.putExtra(MyAppWidgetProvider.KEY_SCROLL_OFFSET, -scrollByAmount);
+        mContext.sendBroadcast(intent);
+
+        // Wait until the update request has been processed
+        try {
+            assertTrue(updateLatch.await(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ie) {
+            fail(ie.getMessage());
+        }
+        // And wait until the underlying ListView has been updated to be visible
+        PollingCheck.waitFor(TEST_TIMEOUT_MS, () -> mListView.getVisibility() == View.VISIBLE);
+
+        // Wait until our ListView has at least one visible child view. At that point we know
+        // that not only the host view is on screen, but also that the list view has completed
+        // its layout pass after having asked its adapter to populate the list content.
+        PollingCheck.waitFor(TEST_TIMEOUT_MS, () -> mListView.getChildCount() > 0);
+
+        // If we're on a really big display, we might be in a situation where the position
+        // we're going to scroll to is already visible. In that case the logic in the rest
+        // of this test will never fire off a listener callback and then fail the test.
+        final int lastVisiblePosition = mListView.getLastVisiblePosition();
+        if (positionToScrollTo <= lastVisiblePosition) {
+            return;
+        }
+
+        boolean result = false;
+        try {
+            result = scrollToPositionLatch.await(20, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Timed out while waiting for the target view to be scrolled into view", result);
+
+        if ((offsetScrollTarget < 0) ||
+                (offsetScrollTarget >= mListView.getFirstVisiblePosition())) {
+            // We can't scroll up because the target is either already visible or negative
+            return;
+        }
+
+        // Now register another scroll listener on our ListView. The listener will notify our latch
+        // when our new "target" item comes into view. If that never happens, the latch will
+        // time out and fail the test.
+        final CountDownLatch scrollByOffsetLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(
+                new ListScrollListener(scrollByOffsetLatch, offsetScrollTarget));
+
+        // Update our atomic boolean to "kick off" the widget provider request to call
+        // setRelativeScrollPosition on our RemoteViews
+        scrollToPositionIsComplete.set(true);
+        try {
+            result = scrollByOffsetLatch.await(20, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Timed out while waiting for the target view to be scrolled into view", result);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
index aefca0f..e044f95 100644
--- a/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
@@ -16,9 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
 import android.content.Context;
 import android.database.Cursor;
 import android.database.MatrixCursor;
@@ -28,6 +25,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ResourceCursorAdapter;
+import android.widget.cts.R;
 
 /**
  * Test {@link ResourceCursorAdapter}.
diff --git a/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java
index e801e93..e09ca08 100644
--- a/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java
@@ -16,9 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
 import android.content.Context;
 import android.database.Cursor;
 import android.database.MatrixCursor;
@@ -28,6 +25,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ResourceCursorTreeAdapter;
+import android.widget.cts.R;
 
 /**
  * Test {@link ResourceCursorTreeAdapter}.
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ScrollViewCtsActivity.java
index b2b51c6..52f7e0f 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 public class ScrollViewCtsActivity extends Activity {
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
index 26510f27..8e38cd5 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
@@ -20,12 +20,6 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
-import android.widget.FrameLayout;
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.app.Activity;
 import android.content.Context;
 import android.cts.util.PollingCheck;
@@ -34,13 +28,16 @@
 import android.test.UiThreadTest;
 import android.util.AttributeSet;
 import android.util.Xml;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
 import android.widget.ScrollView;
 import android.widget.TextView;
+import android.widget.cts.R;
+import android.widget.cts.util.TestUtils;
+
+import org.xmlpull.v1.XmlPullParser;
 
 /**
  * Test {@link ScrollView}.
@@ -75,11 +72,10 @@
         mScrollView = (MyScrollView) mActivity.findViewById(R.id.scroll_view);
 
         // calculate pixel positions from dpi constants.
-        final float density = getActivity().getResources().getDisplayMetrics().density;
-        mItemWidth = (int) (ITEM_WIDTH_DPI * density + 0.5f);
-        mItemHeight = (int) (ITEM_HEIGHT_DPI * density + 0.5f);
-        mPageWidth = (int) (PAGE_WIDTH_DPI * density + 0.5f);
-        mPageHeight = (int) (PAGE_HEIGHT_DPI * density + 0.5f);
+        mItemWidth = TestUtils.dpToPx(mActivity, ITEM_WIDTH_DPI);
+        mItemHeight = TestUtils.dpToPx(mActivity, ITEM_HEIGHT_DPI);
+        mPageWidth = TestUtils.dpToPx(mActivity, PAGE_WIDTH_DPI);
+        mPageHeight = TestUtils.dpToPx(mActivity, PAGE_HEIGHT_DPI);
 
         mScrollBottom = mItemHeight * ITEM_COUNT - mPageHeight;
         mScrollRight = mItemWidth - mPageWidth;
@@ -829,55 +825,34 @@
         }
 
         if (fromY != toY) {
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return isInRange(mScrollView.getScrollY(), fromY, toY);
-                }
-            }.run();
+            PollingCheck.waitFor(() -> isInRange(mScrollView.getScrollY(), fromY, toY));
         }
 
         if (fromX != toX) {
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return isInRange(mScrollView.getScrollX(), fromX, toX);
-                }
-            }.run();
+            PollingCheck.waitFor(() -> isInRange(mScrollView.getScrollX(), fromX, toX));
         }
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return toX == mScrollView.getScrollX() && toY == mScrollView.getScrollY();
-            }
-        }.run();
+        PollingCheck.waitFor(
+                () -> toX == mScrollView.getScrollX() && toY == mScrollView.getScrollY());
     }
 
     private void pollingCheckFling(final int startPosition, final boolean movingDown) {
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                if (movingDown) {
-                    return mScrollView.getScrollY() > startPosition;
-                }
-                return mScrollView.getScrollY() < startPosition;
+        PollingCheck.waitFor(() -> {
+            if (movingDown) {
+                return mScrollView.getScrollY() > startPosition;
             }
-        };
+            return mScrollView.getScrollY() < startPosition;
+        });
 
-        new PollingCheck() {
-            private int mPreviousScrollY = mScrollView.getScrollY();
-
-            @Override
-            protected boolean check() {
-                if (mScrollView.getScrollY() == mPreviousScrollY) {
-                    return true;
-                } else {
-                    mPreviousScrollY = mScrollView.getScrollY();
-                    return false;
-                }
+        final int[] previousScrollY = new int[] { mScrollView.getScrollY() };
+        PollingCheck.waitFor(() -> {
+            if (mScrollView.getScrollY() == previousScrollY[0]) {
+                return true;
+            } else {
+                previousScrollY[0] = mScrollView.getScrollY();
+                return false;
             }
-        }.run();
+        });
     }
 
     public static class MyView extends View {
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/SearchViewCtsActivity.java
similarity index 67%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/SearchViewCtsActivity.java
index 481f5be..5da8a32 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/SearchViewCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.SearchView;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link SearchView} test.
+ */
+public class SearchViewCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.searchview_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/SearchViewTest.java b/tests/tests/widget/src/android/widget/cts/SearchViewTest.java
new file mode 100644
index 0000000..2d0c208
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SearchViewTest.java
@@ -0,0 +1,242 @@
+/*
+ * 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.widget.cts;
+
+import static org.mockito.Mockito.*;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.res.Resources;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.view.inputmethod.EditorInfo;
+import android.widget.SearchView;
+
+/**
+ * Test {@link SearchView}.
+ */
+@MediumTest
+public class SearchViewTest extends ActivityInstrumentationTestCase2<SearchViewCtsActivity> {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private SearchView mSearchView;
+
+    public SearchViewTest() {
+        super("android.widget.cts", SearchViewCtsActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+        mSearchView = (SearchView) mActivity.findViewById(R.id.search_view);
+    }
+
+    @UiThreadTest
+    public void testConstructor() {
+        new SearchView(mActivity);
+
+        new SearchView(mActivity, null);
+
+        new SearchView(mActivity, null, android.R.attr.searchViewStyle);
+
+        new SearchView(mActivity, null, 0, android.R.style.Widget_Material_SearchView);
+
+        new SearchView(mActivity, null, 0, android.R.style.Widget_Material_Light_SearchView);
+    }
+
+    @UiThreadTest
+    public void testAttributesFromXml() {
+        SearchView searchViewWithAttributes =
+                (SearchView) mActivity.findViewById(R.id.search_view_with_defaults);
+        assertEquals(mActivity.getString(R.string.search_query_hint),
+                searchViewWithAttributes.getQueryHint());
+        assertFalse(searchViewWithAttributes.isIconfiedByDefault());
+        assertEquals(EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS | EditorInfo.TYPE_CLASS_TEXT,
+                searchViewWithAttributes.getInputType());
+        assertEquals(EditorInfo.IME_ACTION_DONE, searchViewWithAttributes.getImeOptions());
+        assertEquals(mActivity.getResources().getDimensionPixelSize(R.dimen.search_view_max_width),
+                searchViewWithAttributes.getMaxWidth());
+    }
+
+    public void testAccessIconified() {
+        mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(true));
+        assertTrue(mSearchView.isIconified());
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(false));
+        assertFalse(mSearchView.isIconified());
+    }
+
+    public void testAccessIconifiedByDefault() {
+        mInstrumentation.runOnMainSync(() -> mSearchView.setIconifiedByDefault(true));
+        assertTrue(mSearchView.isIconfiedByDefault());
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setIconifiedByDefault(false));
+        assertFalse(mSearchView.isIconfiedByDefault());
+    }
+
+    public void testDenyIconifyingNonInconifiableView() {
+        mInstrumentation.runOnMainSync(() -> {
+            mSearchView.setIconifiedByDefault(false);
+            mSearchView.setIconified(false);
+        });
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(true));
+        mInstrumentation.waitForIdleSync();
+
+        // Since our search view is marked with iconifiedByDefault=false, call to setIconified
+        // with true us going to be ignored, as detailed in the class-level documentation of
+        // SearchView.
+        assertFalse(mSearchView.isIconified());
+    }
+
+    public void testDenyIconifyingInconifiableView() {
+        mInstrumentation.runOnMainSync(() -> {
+            mSearchView.setIconifiedByDefault(true);
+            mSearchView.setIconified(false);
+        });
+
+        final SearchView.OnCloseListener mockDenyCloseListener =
+                mock(SearchView.OnCloseListener.class);
+        when(mockDenyCloseListener.onClose()).thenReturn(Boolean.TRUE);
+        mSearchView.setOnCloseListener(mockDenyCloseListener);
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(true));
+        mInstrumentation.waitForIdleSync();
+
+        // Our mock listener is configured to return true from its onClose, thereby preventing
+        // the iconify request to be completed. Check that the listener was called and that the
+        // search view is not iconified.
+        verify(mockDenyCloseListener, times(1)).onClose();
+        assertFalse(mSearchView.isIconified());
+    }
+
+    public void testAllowIconifyingInconifiableView() {
+        mInstrumentation.runOnMainSync(() -> {
+            mSearchView.setIconifiedByDefault(true);
+            mSearchView.setIconified(false);
+        });
+
+        final SearchView.OnCloseListener mockAllowCloseListener =
+                mock(SearchView.OnCloseListener.class);
+        when(mockAllowCloseListener.onClose()).thenReturn(Boolean.FALSE);
+        mSearchView.setOnCloseListener(mockAllowCloseListener);
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(true));
+        mInstrumentation.waitForIdleSync();
+
+        // Our mock listener is configured to return false from its onClose, thereby allowing
+        // the iconify request to be completed. Check that the listener was called and that the
+        // search view is not iconified.
+        verify(mockAllowCloseListener, times(1)).onClose();
+        assertTrue(mSearchView.isIconified());
+    }
+
+    public void testAccessMaxWidth() {
+        final Resources res = mActivity.getResources();
+        final int maxWidth1 = res.getDimensionPixelSize(R.dimen.search_view_max_width);
+        final int maxWidth2 = res.getDimensionPixelSize(R.dimen.search_view_max_width2);
+
+        // Set search view to not be iconified before running max-width tests
+        mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(false));
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setMaxWidth(maxWidth1));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(maxWidth1, mSearchView.getMaxWidth());
+        assertTrue(mSearchView.getWidth() <= maxWidth1);
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setMaxWidth(maxWidth2));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(maxWidth2, mSearchView.getMaxWidth());
+        assertTrue(mSearchView.getWidth() <= maxWidth2);
+    }
+
+    public void testAccessQuery() {
+        mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(false));
+
+        final SearchView.OnQueryTextListener mockQueryTextListener =
+                mock(SearchView.OnQueryTextListener.class);
+        when(mockQueryTextListener.onQueryTextSubmit(anyString())).thenReturn(Boolean.TRUE);
+        mSearchView.setOnQueryTextListener(mockQueryTextListener);
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("alpha", false));
+        assertTrue(TextUtils.equals("alpha", mSearchView.getQuery()));
+        // Since we passed false as the second parameter to setQuery, our query text listener
+        // should have been invoked only with text change
+        verify(mockQueryTextListener, times(1)).onQueryTextChange("alpha");
+        verify(mockQueryTextListener, never()).onQueryTextSubmit(anyString());
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("beta", true));
+        assertTrue(TextUtils.equals("beta", mSearchView.getQuery()));
+        // Since we passed true as the second parameter to setQuery, our query text listener
+        // should have been invoked on both callbacks
+        verify(mockQueryTextListener, times(1)).onQueryTextChange("beta");
+        verify(mockQueryTextListener, times(1)).onQueryTextSubmit("beta");
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("gamma", true));
+        assertTrue(TextUtils.equals("gamma", mSearchView.getQuery()));
+        // Since we passed true as the second parameter to setQuery, our query text listener
+        // should have been invoked on both callbacks
+        verify(mockQueryTextListener, times(1)).onQueryTextChange("gamma");
+        verify(mockQueryTextListener, times(1)).onQueryTextSubmit("gamma");
+
+        verifyNoMoreInteractions(mockQueryTextListener);
+    }
+
+    public void testAccessQueryHint() {
+        mInstrumentation.runOnMainSync(() -> mSearchView.setQueryHint("hint 1"));
+        assertTrue(TextUtils.equals("hint 1", mSearchView.getQueryHint()));
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setQueryHint("hint 2"));
+        assertTrue(TextUtils.equals("hint 2", mSearchView.getQueryHint()));
+    }
+
+    public void testAccessInputType() {
+        mInstrumentation.runOnMainSync(() ->
+                mSearchView.setInputType(InputType.TYPE_CLASS_NUMBER
+                    | InputType.TYPE_NUMBER_FLAG_DECIMAL
+                    | InputType.TYPE_NUMBER_FLAG_SIGNED));
+        assertEquals(InputType.TYPE_CLASS_NUMBER
+                | InputType.TYPE_NUMBER_FLAG_DECIMAL
+                | InputType.TYPE_NUMBER_FLAG_SIGNED, mSearchView.getInputType());
+
+        mInstrumentation.runOnMainSync(() ->
+                mSearchView.setInputType(InputType.TYPE_CLASS_TEXT
+                        | InputType.TYPE_TEXT_FLAG_CAP_WORDS));
+        assertEquals(InputType.TYPE_CLASS_TEXT
+                | InputType.TYPE_TEXT_FLAG_CAP_WORDS, mSearchView.getInputType());
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setInputType(InputType.TYPE_CLASS_PHONE));
+        assertEquals(InputType.TYPE_CLASS_PHONE, mSearchView.getInputType());
+    }
+
+    public void testAccessImeOptions() {
+        mInstrumentation.runOnMainSync(() -> mSearchView.setImeOptions(EditorInfo.IME_ACTION_GO));
+        assertEquals(EditorInfo.IME_ACTION_GO, mSearchView.getImeOptions());
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setImeOptions(EditorInfo.IME_ACTION_DONE));
+        assertEquals(EditorInfo.IME_ACTION_DONE, mSearchView.getImeOptions());
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setImeOptions(EditorInfo.IME_NULL));
+        assertEquals(EditorInfo.IME_NULL, mSearchView.getImeOptions());
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
new file mode 100644
index 0000000..1bebb01
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.widget.cts;
+
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.cts.util.PollingCheck;
+import android.cts.util.CtsTouchUtils;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.BaseColumns;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.TextUtils;
+import android.widget.CursorAdapter;
+import android.widget.SearchView;
+import android.widget.SimpleCursorAdapter;
+
+/**
+ * Test {@link SearchView} with {@link Cursor}-backed suggestions adapter.
+ */
+@MediumTest
+public class SearchView_CursorTest extends ActivityInstrumentationTestCase2<SearchViewCtsActivity> {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private SearchView mSearchView;
+
+    private static final String TEXT_COLUMN_NAME = "text";
+    private String[] mTextContent;
+
+    private CursorAdapter mSuggestionsAdapter;
+
+    protected class MyQueryTextListener implements SearchView.OnQueryTextListener {
+        @Override
+        public boolean onQueryTextSubmit(String s) {
+            return false;
+        }
+
+        @Override
+        public boolean onQueryTextChange(String s) {
+            if (mSuggestionsAdapter == null) {
+                return false;
+            }
+
+            final MatrixCursor c = new MatrixCursor(
+                    new String[] { BaseColumns._ID, TEXT_COLUMN_NAME} );
+            for (int i = 0; i < mTextContent.length; i++) {
+                if (mTextContent[i].toLowerCase().startsWith(s.toLowerCase())) {
+                    c.addRow(new Object[]{i, mTextContent[i]});
+                }
+            }
+            mSuggestionsAdapter.swapCursor(c);
+            return false;
+        }
+    }
+
+    protected class MySuggestionListener implements SearchView.OnSuggestionListener {
+        @Override
+        public boolean onSuggestionSelect(int position) {
+            return false;
+        }
+
+        @Override
+        public boolean onSuggestionClick(int position) {
+            if (mSuggestionsAdapter != null) {
+                final Cursor cursor = mSuggestionsAdapter.getCursor();
+                if (cursor != null) {
+                    cursor.moveToPosition(position);
+                    mSearchView.setQuery(cursor.getString(1), false);
+                }
+            }
+            return false;
+        }
+    }
+
+    public SearchView_CursorTest() {
+        super("android.widget.cts", SearchViewCtsActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+        mSearchView = (SearchView) mActivity.findViewById(R.id.search_view);
+
+        // Local test data for the tests
+        mTextContent = new String[] { "Akon", "Bono", "Ciara", "Dido", "Diplo" };
+
+        mInstrumentation.runOnMainSync(() -> {
+            // Use an adapter with our custom layout for each entry. The adapter "maps"
+            // the content of the text column of our cursor to the @id/text1 view in the
+            // layout.
+            mSuggestionsAdapter = new SimpleCursorAdapter(
+                    mActivity,
+                    R.layout.searchview_suggestion_item,
+                    null,
+                    new String[] { TEXT_COLUMN_NAME },
+                    new int[] { android.R.id.text1 },
+                    CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
+            mSearchView.setSuggestionsAdapter(mSuggestionsAdapter);
+        });
+    }
+
+    public void testSuggestionFiltering() {
+        final SearchView.OnQueryTextListener mockQueryTextListener =
+                spy(new MyQueryTextListener());
+        when(mockQueryTextListener.onQueryTextChange(anyString())).thenCallRealMethod();
+
+        mInstrumentation.runOnMainSync(() -> {
+                    mSearchView.setIconifiedByDefault(false);
+                    mSearchView.setOnQueryTextListener(mockQueryTextListener);
+                    mSearchView.requestFocus();
+                });
+
+        assertTrue(mSearchView.hasFocus());
+        assertEquals(mSuggestionsAdapter, mSearchView.getSuggestionsAdapter());
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("Bon", false));
+        verify(mockQueryTextListener, times(1)).onQueryTextChange("Bon");
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("Di", false));
+        verify(mockQueryTextListener, times(1)).onQueryTextChange("Di");
+    }
+
+    public void testSuggestionSelection() {
+        final SearchView.OnSuggestionListener mockSuggestionListener =
+                spy(new MySuggestionListener());
+        when(mockSuggestionListener.onSuggestionClick(anyInt())).thenCallRealMethod();
+
+        final SearchView.OnQueryTextListener mockQueryTextListener =
+                spy(new MyQueryTextListener());
+        when(mockQueryTextListener.onQueryTextChange(anyString())).thenCallRealMethod();
+
+        mInstrumentation.runOnMainSync(() -> {
+                    mSearchView.setIconifiedByDefault(false);
+                    mSearchView.setOnQueryTextListener(mockQueryTextListener);
+                    mSearchView.setOnSuggestionListener(mockSuggestionListener);
+                    mSearchView.requestFocus();
+                });
+
+        assertTrue(mSearchView.hasFocus());
+        assertEquals(mSuggestionsAdapter, mSearchView.getSuggestionsAdapter());
+
+        mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("Di", false));
+        mInstrumentation.waitForIdleSync();
+        verify(mockQueryTextListener, times(1)).onQueryTextChange("Di");
+
+        // Emulate click on the first suggestion - which should be Dido
+        final int suggestionRowHeight = mActivity.getResources().getDimensionPixelSize(
+                R.dimen.search_view_suggestion_row_height);
+        CtsTouchUtils.emulateTapOnScreen(mInstrumentation, mSearchView, mSearchView.getWidth() / 2,
+                mSearchView.getHeight() + suggestionRowHeight / 2);
+
+        // At this point we expect the click on the first suggestion to have activated a sequence
+        // of events that ends up in our suggestion listener that sets the full suggestion text
+        // as the current query. Some parts of this sequence of events are asynchronous, and those
+        // are not "caught" by Instrumentation.waitForIdleSync - which is in general not a very
+        // reliable way to wait for everything to be completed. As such, we are using our own
+        // polling check mechanism to wait until the search view's query is the fully completed
+        // suggestion for Dido. This check will time out and fail after a few seconds if anything
+        // goes wrong during the processing of the emulated tap and the code never gets to our
+        // suggestion listener
+        PollingCheck.waitFor(() -> TextUtils.equals("Dido", mSearchView.getQuery()));
+
+        // Just to be sure, verify that our spy suggestion listener was called
+        verify(mockSuggestionListener, times(1)).onSuggestionClick(0);
+        verifyNoMoreInteractions(mockSuggestionListener);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/SeekBarCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SeekBarCtsActivity.java
index e22b910..5dcbe56 100644
--- a/tests/tests/widget/src/android/widget/cts/SeekBarCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/SeekBarCtsActivity.java
@@ -16,8 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
@@ -28,7 +26,7 @@
  */
 public class SeekBarCtsActivity extends Activity {
     /**
-     * Called with the activity is first created.
+     * Called when the activity is first created.
      */
     @Override
     public void onCreate(Bundle savedInstanceState) {
diff --git a/tests/tests/widget/src/android/widget/cts/SeekBarTest.java b/tests/tests/widget/src/android/widget/cts/SeekBarTest.java
index 9182bcc..fb9a5e9 100644
--- a/tests/tests/widget/src/android/widget/cts/SeekBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SeekBarTest.java
@@ -16,20 +16,20 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.view.MotionEvent;
 import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
 
 /**
  * Test {@link SeekBar}.
  */
+@SmallTest
 public class SeekBarTest extends ActivityInstrumentationTestCase2<SeekBarCtsActivity> {
     private SeekBar mSeekBar;
 
@@ -55,13 +55,21 @@
         new SeekBar(mActivity, null);
 
         new SeekBar(mActivity, null, android.R.attr.seekBarStyle);
+
+        new SeekBar(mActivity, null, 0, android.R.style.Widget_DeviceDefault_SeekBar);
+
+        new SeekBar(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Light_SeekBar);
+
+        new SeekBar(mActivity, null, 0, android.R.style.Widget_Material_SeekBar);
+
+        new SeekBar(mActivity, null, 0, android.R.style.Widget_Material_Light_SeekBar);
     }
 
     public void testSetOnSeekBarChangeListener() {
-        MockOnSeekBarListener listener = new MockOnSeekBarListener();
+        SeekBar.OnSeekBarChangeListener mockChangeListener =
+                mock(SeekBar.OnSeekBarChangeListener.class);
 
-        mSeekBar.setOnSeekBarChangeListener(listener);
-        listener.reset();
+        mSeekBar.setOnSeekBarChangeListener(mockChangeListener);
         long downTime = SystemClock.uptimeMillis();
         long eventTime = SystemClock.uptimeMillis();
         int seekBarXY[] = new int[2];
@@ -70,66 +78,28 @@
                 seekBarXY[0], seekBarXY[1], 0);
         mInstrumentation.sendPointerSync(event);
         mInstrumentation.waitForIdleSync();
-        assertTrue(listener.hasCalledOnStartTrackingTouch());
+        verify(mockChangeListener, times(1)).onStartTrackingTouch(mSeekBar);
         // while starting to track, the progress is changed also
-        assertTrue(listener.hasCalledOnProgressChanged());
+        verify(mockChangeListener, atLeastOnce()).onProgressChanged(eq(mSeekBar), anyInt(),
+                eq(true));
 
-        listener.reset();
+        reset(mockChangeListener);
         downTime = SystemClock.uptimeMillis();
         eventTime = SystemClock.uptimeMillis();
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
                 seekBarXY[0] + (mSeekBar.getWidth() >> 1), seekBarXY[1], 0);
         mInstrumentation.sendPointerSync(event);
         mInstrumentation.waitForIdleSync();
-        assertTrue(listener.hasCalledOnProgressChanged());
+        verify(mockChangeListener, atLeastOnce()).onProgressChanged(eq(mSeekBar), anyInt(),
+                eq(true));
 
-        listener.reset();
+        reset(mockChangeListener);
         downTime = SystemClock.uptimeMillis();
         eventTime = SystemClock.uptimeMillis();
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP,
                 seekBarXY[0] + (mSeekBar.getWidth() >> 1), seekBarXY[1], 0);
         mInstrumentation.sendPointerSync(event);
         mInstrumentation.waitForIdleSync();
-        assertTrue(listener.hasCalledOnStopTrackingTouch());
-
-        mSeekBar.setOnSeekBarChangeListener(null);
-    }
-
-    private class MockOnSeekBarListener implements OnSeekBarChangeListener {
-        private boolean mHasCalledOnProgressChanged;
-
-        private boolean mHasCalledOnStartTrackingTouch;
-
-        private boolean mHasCalledOnStopTrackingTouch;
-
-        public boolean hasCalledOnProgressChanged() {
-            return mHasCalledOnProgressChanged;
-        }
-
-        public boolean hasCalledOnStartTrackingTouch() {
-            return mHasCalledOnStartTrackingTouch;
-        }
-
-        public boolean hasCalledOnStopTrackingTouch() {
-            return mHasCalledOnStopTrackingTouch;
-        }
-
-        public void reset(){
-            mHasCalledOnProgressChanged = false;
-            mHasCalledOnStartTrackingTouch = false;
-            mHasCalledOnStopTrackingTouch = false;
-        }
-
-        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
-            mHasCalledOnProgressChanged = true;
-        }
-
-        public void onStartTrackingTouch(SeekBar seekBar) {
-            mHasCalledOnStartTrackingTouch = true;
-        }
-
-        public void onStopTrackingTouch(SeekBar seekBar) {
-            mHasCalledOnStopTrackingTouch = true;
-        }
+        verify(mockChangeListener, times(1)).onStopTrackingTouch(mSeekBar);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
index 5a9af25..9911b55 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
@@ -17,8 +17,6 @@
 package android.widget.cts;
 
 import android.R;
-
-
 import android.content.Context;
 import android.content.res.Resources.Theme;
 import android.cts.util.WidgetTestUtils;
@@ -31,9 +29,9 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.SimpleAdapter;
+import android.widget.SimpleAdapter.ViewBinder;
 import android.widget.TextView;
 import android.widget.TwoLineListItem;
-import android.widget.SimpleAdapter.ViewBinder;
 
 import java.util.ArrayList;
 import java.util.HashMap;
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
index 469e581..9182a48 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
@@ -16,9 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
 import android.content.Context;
 import android.cts.util.WidgetTestUtils;
 import android.database.Cursor;
@@ -33,9 +30,10 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.SimpleCursorAdapter;
-import android.widget.TextView;
 import android.widget.SimpleCursorAdapter.CursorToStringConverter;
 import android.widget.SimpleCursorAdapter.ViewBinder;
+import android.widget.TextView;
+import android.widget.cts.R;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
index 02941fa..286bc2a 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
@@ -16,9 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
 import android.content.Context;
 import android.cts.util.WidgetTestUtils;
 import android.database.Cursor;
@@ -31,6 +28,7 @@
 import android.widget.ImageView;
 import android.widget.SimpleCursorTreeAdapter;
 import android.widget.TextView;
+import android.widget.cts.R;
 
 /**
  * Test {@link SimpleCursorTreeAdapter}.
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java
index 674f427..782c85e 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java
@@ -17,13 +17,10 @@
 package android.widget.cts;
 
 import android.R;
-
-
 import android.content.Context;
 import android.test.InstrumentationTestCase;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.SimpleExpandableListAdapter;
 import android.widget.TextView;
@@ -31,7 +28,6 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 
 /**
  * Test {@link SimpleExpandableListAdapter}.
diff --git a/tests/tests/widget/src/android/widget/cts/SlidingDrawerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SlidingDrawerCtsActivity.java
index d1362c1..338c577 100644
--- a/tests/tests/widget/src/android/widget/cts/SlidingDrawerCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/SlidingDrawerCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 public class SlidingDrawerCtsActivity extends Activity {
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java b/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
index 2af1b06..d2f25b9 100644
--- a/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
@@ -16,29 +16,27 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
-import android.content.Context;
 import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.util.AttributeSet;
 import android.util.Xml;
-import android.view.MotionEvent;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.SlidingDrawer;
 import android.widget.TextView;
-import android.widget.SlidingDrawer.OnDrawerCloseListener;
-import android.widget.SlidingDrawer.OnDrawerOpenListener;
-import android.widget.SlidingDrawer.OnDrawerScrollListener;
+
+import org.mockito.InOrder;
+import org.mockito.invocation.InvocationOnMock;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test {@link SlidingDrawer}.
@@ -48,7 +46,6 @@
 
     private static final long TEST_TIMEOUT = 5000L;
     private Activity mActivity;
-    private Object mLock;
 
     public SlidingDrawerTest() {
         super("android.widget.cts", SlidingDrawerCtsActivity.class);
@@ -58,7 +55,6 @@
     protected void setUp() throws Exception {
         super.setUp();
         mActivity = getActivity();
-        mLock = new Object();
     }
 
     @UiThreadTest
@@ -118,40 +114,20 @@
         assertFalse(drawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                drawer.animateOpen();
-            }
-        });
+        runTestOnUiThread(drawer::animateOpen);
         assertTrue(drawer.isMoving());
-        assertOpened(false, drawer);
         assertEquals(View.GONE, content.getVisibility());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !drawer.isMoving();
-            }
-        }.run();
-        assertOpened(true, drawer);
+        PollingCheck.waitFor(() -> !drawer.isMoving());
+        PollingCheck.waitFor(drawer::isOpened);
         assertEquals(View.VISIBLE, content.getVisibility());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                drawer.animateClose();
-            }
-        });
+        runTestOnUiThread(drawer::animateClose);
         assertTrue(drawer.isMoving());
-        assertOpened(true, drawer);
         assertEquals(View.GONE, content.getVisibility());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !drawer.isMoving();
-            }
-        }.run();
-        assertOpened(false, drawer);
+        PollingCheck.waitFor(() -> !drawer.isMoving());
+        PollingCheck.waitFor(() -> !drawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
     }
 
@@ -162,52 +138,23 @@
         assertFalse(drawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                drawer.animateToggle();
-            }
-        });
+        runTestOnUiThread(drawer::animateToggle);
         assertTrue(drawer.isMoving());
-        assertOpened(false, drawer);
         assertEquals(View.GONE, content.getVisibility());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !drawer.isMoving();
-            }
-        }.run();
-        assertOpened(true, drawer);
+        PollingCheck.waitFor(() -> !drawer.isMoving());
+        PollingCheck.waitFor(drawer::isOpened);
         assertEquals(View.VISIBLE, content.getVisibility());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                drawer.animateToggle();
-            }
-        });
+        runTestOnUiThread(drawer::animateToggle);
         assertTrue(drawer.isMoving());
-        assertOpened(true, drawer);
         assertEquals(View.GONE, content.getVisibility());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !drawer.isMoving();
-            }
-        }.run();
-        assertOpened(false, drawer);
+        PollingCheck.waitFor(() -> !drawer.isMoving());
+        PollingCheck.waitFor(() -> !drawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
     }
 
-    private void assertOpened(final boolean opened, final SlidingDrawer drawer) {
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return drawer.isOpened() == opened;
-            }
-        }.run();
-    }
-
     @UiThreadTest
     public void testToggle() {
         SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
@@ -254,56 +201,61 @@
     @UiThreadTest
     public void testSetOnDrawerOpenListener() {
         SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        MockOnDrawerOpenListener listener = new MockOnDrawerOpenListener();
-        drawer.setOnDrawerOpenListener(listener);
+        SlidingDrawer.OnDrawerOpenListener mockOpenListener =
+                mock(SlidingDrawer.OnDrawerOpenListener.class);
+        drawer.setOnDrawerOpenListener(mockOpenListener);
 
-        assertFalse(listener.hadOpenedDrawer());
+        verifyZeroInteractions(mockOpenListener);
 
         drawer.open();
-        assertTrue(listener.hadOpenedDrawer());
+        verify(mockOpenListener, times(1)).onDrawerOpened();
     }
 
     @UiThreadTest
     public void testSetOnDrawerCloseListener() {
         SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        MockOnDrawerCloseListener listener = new MockOnDrawerCloseListener();
-        drawer.setOnDrawerCloseListener(listener);
+        SlidingDrawer.OnDrawerCloseListener mockCloseListener =
+                mock(SlidingDrawer.OnDrawerCloseListener.class);
+        drawer.setOnDrawerCloseListener(mockCloseListener);
 
-        assertFalse(listener.hadClosedDrawer());
+        verifyZeroInteractions(mockCloseListener);
 
         drawer.open();
-        assertFalse(listener.hadClosedDrawer());
+        verifyZeroInteractions(mockCloseListener);
 
         drawer.close();
-        assertTrue(listener.hadClosedDrawer());
+        verify(mockCloseListener, times(1)).onDrawerClosed();
     }
 
     public void testSetOnDrawerScrollListener() throws Throwable {
         final SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        MockOnDrawerScrollListener listener = new MockOnDrawerScrollListener();
-        drawer.setOnDrawerScrollListener(listener);
-        assertFalse(listener.hadStartedScroll());
-        assertFalse(listener.hadEndedScroll());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                drawer.animateOpen();
-            }
-        });
-        if ( !listener.hadStartedScroll() ) {
-            synchronized (mLock) {
-                mLock.wait(TEST_TIMEOUT);
-            }
-        }
-        assertTrue(listener.hadStartedScroll());
+        final CountDownLatch countDownLatch = new CountDownLatch(2);
+        final SlidingDrawer.OnDrawerScrollListener mockScrollListener =
+                mock(SlidingDrawer.OnDrawerScrollListener.class);
+        doAnswer((InvocationOnMock invocation) -> {
+            countDownLatch.countDown();
+            return null;
+        }).when(mockScrollListener).onScrollStarted();
+        doAnswer((InvocationOnMock invocation) -> {
+            countDownLatch.countDown();
+            return null;
+        }).when(mockScrollListener).onScrollEnded();
+        drawer.setOnDrawerScrollListener(mockScrollListener);
 
-        if ( !listener.hadEndedScroll() ) {
-            synchronized (mLock) {
-                mLock.wait(TEST_TIMEOUT);
-            }
+        runTestOnUiThread(drawer::animateOpen);
+
+        try {
+            countDownLatch.await(2 * TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException ie) {
+            // Do nothing as we're about to verify that both callbacks have been called
+            // in any case
         }
-        assertTrue(listener.hadStartedScroll());
-        assertTrue(listener.hadEndedScroll());
+
+        InOrder inOrder = inOrder(mockScrollListener);
+        inOrder.verify(mockScrollListener).onScrollStarted();
+        inOrder.verify(mockScrollListener).onScrollEnded();
+        verifyNoMoreInteractions(mockScrollListener);
     }
 
     public void testOnLayout() {
@@ -329,56 +281,4 @@
     public void testOnTouchEvent() {
         // onTouchEvent() is implementation details, do NOT test
     }
-
-    private static final class MockOnDrawerOpenListener implements OnDrawerOpenListener {
-        private boolean mHadOpenedDrawer = false;
-
-        public void onDrawerOpened() {
-            mHadOpenedDrawer = true;
-        }
-
-        public boolean hadOpenedDrawer() {
-            return mHadOpenedDrawer;
-        }
-    }
-
-    private static final class MockOnDrawerCloseListener implements OnDrawerCloseListener {
-        private boolean mHadClosedDrawer = false;
-
-        public void onDrawerClosed() {
-            mHadClosedDrawer = true;
-        }
-
-        public boolean hadClosedDrawer() {
-            return mHadClosedDrawer;
-        }
-    }
-
-    private final class MockOnDrawerScrollListener implements OnDrawerScrollListener {
-        private boolean mHadEndedScroll = false;
-        private boolean mHadStartedScroll = false;
-
-        public void onScrollEnded() {
-            synchronized (mLock) {
-                assertTrue(mHadStartedScroll);
-                mHadEndedScroll = true;
-                mLock.notify();
-            }
-        }
-
-        public void onScrollStarted() {
-            synchronized (mLock) {
-                mHadStartedScroll = true;
-                mLock.notify();
-            }
-        }
-
-        public boolean hadEndedScroll() {
-            return mHadEndedScroll;
-        }
-
-        public boolean hadStartedScroll() {
-            return mHadStartedScroll;
-        }
-    }
 }
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/SpinnerCtsActivity.java
similarity index 68%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/SpinnerCtsActivity.java
index 481f5be..16fb30e 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/SpinnerCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.Spinner;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link Spinner} test.
+ */
+public class SpinnerCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.spinner_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
index eea1e3e..ca0bd0c 100644
--- a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
@@ -16,101 +16,164 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.mockito.Mockito.*;
 
-
+import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.content.Context;
+import android.app.Instrumentation;
+import android.cts.util.CtsTouchUtils;
+import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.Resources.Theme;
+import android.cts.util.WidgetTestUtils;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.Spinner;
+import android.widget.cts.util.TestUtils;
 
 /**
  * Test {@link Spinner}.
  */
-public class SpinnerTest extends ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
-    private Context mTargetContext;
+@MediumTest
+public class SpinnerTest extends ActivityInstrumentationTestCase2<SpinnerCtsActivity> {
+    private Activity mActivity;
+    private Spinner mSpinnerDialogMode;
+    private Spinner mSpinnerDropdownMode;
 
     public SpinnerTest() {
-        super("android.widget.cts", RelativeLayoutCtsActivity.class);
+        super("android.widget.cts", SpinnerCtsActivity.class);
     }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mTargetContext = getInstrumentation().getTargetContext();
+
+        mActivity = getActivity();
+        mSpinnerDialogMode = (Spinner) mActivity.findViewById(R.id.spinner_dialog_mode);
+        mSpinnerDropdownMode = (Spinner) mActivity.findViewById(R.id.spinner_dropdown_mode);
     }
 
-    @UiThreadTest
     public void testConstructor() {
-        new Spinner(mTargetContext);
+        new Spinner(mActivity);
 
-        new Spinner(mTargetContext, null);
+        new Spinner(mActivity, null);
 
-        new Spinner(mTargetContext, null, android.R.attr.spinnerStyle);
+        new Spinner(mActivity, null, android.R.attr.spinnerStyle);
 
-        new Spinner(mTargetContext, Spinner.MODE_DIALOG);
+        new Spinner(mActivity, Spinner.MODE_DIALOG);
 
-        new Spinner(mTargetContext, null, android.R.attr.spinnerStyle,
+        new Spinner(mActivity, Spinner.MODE_DROPDOWN);
+
+        new Spinner(mActivity, null, android.R.attr.spinnerStyle, Spinner.MODE_DIALOG);
+
+        new Spinner(mActivity, null, android.R.attr.spinnerStyle, Spinner.MODE_DROPDOWN);
+
+        new Spinner(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Spinner,
                 Spinner.MODE_DIALOG);
 
-        new Spinner(mTargetContext, null, android.R.attr.spinnerStyle, 0,
+        new Spinner(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Spinner,
+                Spinner.MODE_DROPDOWN);
+
+        new Spinner(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Light_Spinner,
                 Spinner.MODE_DIALOG);
 
-        new Spinner(mTargetContext, null, android.R.attr.spinnerStyle, 0,
-                Spinner.MODE_DIALOG, mTargetContext.getTheme());
+        new Spinner(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Light_Spinner,
+                Spinner.MODE_DROPDOWN);
 
-        Spinner spinner = (Spinner) getActivity().findViewById(R.id.spinner1);
-        assertEquals(mTargetContext.getString(R.string.text_view_hello), spinner.getPrompt());
+        new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Spinner,
+                Spinner.MODE_DIALOG);
+
+        new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Spinner,
+                Spinner.MODE_DROPDOWN);
+
+        new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Spinner_Underlined,
+                Spinner.MODE_DIALOG);
+
+        new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Spinner_Underlined,
+                Spinner.MODE_DROPDOWN);
+
+        new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Light_Spinner,
+                Spinner.MODE_DIALOG);
+
+        new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Light_Spinner,
+                Spinner.MODE_DROPDOWN);
+
+        new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Light_Spinner_Underlined,
+                Spinner.MODE_DIALOG);
+
+        new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Light_Spinner_Underlined,
+                Spinner.MODE_DROPDOWN);
+
+        final Resources.Theme popupTheme = mActivity.getResources().newTheme();
+        popupTheme.applyStyle(android.R.style.Theme_Material, true);
+
+        new Spinner(mActivity, null, android.R.attr.spinnerStyle, 0, Spinner.MODE_DIALOG,
+                popupTheme);
+
+        new Spinner(mActivity, null, android.R.attr.spinnerStyle, 0, Spinner.MODE_DROPDOWN,
+                popupTheme);
     }
 
-    @UiThreadTest
-    public void testGetBaseline() {
-        Spinner spinner = new Spinner(mTargetContext);
-
+    private void verifyGetBaseline(Spinner spinner) {
         assertEquals(-1, spinner.getBaseline());
 
-        spinner = (Spinner) getActivity().findViewById(R.id.spinner1);
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mTargetContext,
-                android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        spinner.setAdapter(adapter);
-        assertTrue(spinner.getBaseline() > 0);
+        getInstrumentation().runOnMainSync(() -> {
+            spinner.setAdapter(adapter);
+            assertTrue(spinner.getBaseline() > 0);
+        });
     }
 
-    @UiThreadTest
-    public void testSetOnItemClickListener() {
-        Spinner spinner = new Spinner(mTargetContext);
+    public void testGetBaseline() {
+        verifyGetBaseline(mSpinnerDialogMode);
+        verifyGetBaseline(mSpinnerDropdownMode);
+    }
 
+    private void verifySetOnItemClickListener(Spinner spinner) {
         try {
             spinner.setOnItemClickListener(null);
             fail("Should throw RuntimeException");
         } catch (RuntimeException e) {
         }
+
+        try {
+            spinner.setOnItemClickListener(mock(Spinner.OnItemClickListener.class));
+            fail("Should throw RuntimeException");
+        } catch (RuntimeException e) {
+        }
     }
 
-    @UiThreadTest
+    public void testSetOnItemClickListener() {
+        verifySetOnItemClickListener(mSpinnerDialogMode);
+        verifySetOnItemClickListener(mSpinnerDropdownMode);
+    }
+
+    private void verifyPerformClick(Spinner spinner) {
+        getInstrumentation().runOnMainSync(() -> assertTrue(spinner.performClick()));
+    }
+
     public void testPerformClick() {
-        final Spinner spinner = (Spinner) getActivity().findViewById(R.id.spinner1);
-
-        assertTrue(spinner.performClick());
-
-        // TODO: no description for the expected result for this method in its javadoc, issue?
-        // Or do UI check?
+        verifyPerformClick(mSpinnerDialogMode);
+        verifyPerformClick(mSpinnerDropdownMode);
     }
 
-    @UiThreadTest
-    public void testOnClick() {
-        Spinner spinner = new Spinner(mTargetContext);
+    private void verifyOnClick(Spinner spinner) {
         // normal value
         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
         AlertDialog alertDialog = builder.show();
         assertTrue(alertDialog.isShowing());
+
         spinner.onClick(alertDialog, 10);
         assertEquals(10, spinner.getSelectedItemPosition());
         assertFalse(alertDialog.isShowing());
@@ -125,32 +188,42 @@
         Dialog dialog = new Dialog(getActivity());
         dialog.show();
         assertTrue(dialog.isShowing());
+
         spinner.onClick(dialog, -10);
         assertEquals(-10, spinner.getSelectedItemPosition());
         assertFalse(dialog.isShowing());
     }
 
     @UiThreadTest
-    public void testAccessPrompt() {
+    public void testOnClick() {
+        verifyOnClick(mSpinnerDialogMode);
+        verifyOnClick(mSpinnerDropdownMode);
+    }
+
+    private void verifyAccessPrompt(Spinner spinner) {
+        final String initialPrompt = mActivity.getString(R.string.text_view_hello);
+        assertEquals(initialPrompt, spinner.getPrompt());
+
+        final Instrumentation instrumentation = getInstrumentation();
         final String promptText = "prompt text";
 
-        Spinner spinner = new Spinner(mTargetContext);
-
-        spinner.setPrompt(promptText);
+        instrumentation.runOnMainSync(() -> spinner.setPrompt(promptText));
         assertEquals(promptText, spinner.getPrompt());
 
         spinner.setPrompt(null);
         assertNull(spinner.getPrompt());
-
-        // TODO: find the dialog and get its title to assert whether setPrompt() takes effect?
     }
 
-    @UiThreadTest
-    public void testSetPromptId() {
-        Spinner spinner = new Spinner(mTargetContext);
+    public void testAccessPrompt() {
+        verifyAccessPrompt(mSpinnerDialogMode);
+        verifyAccessPrompt(mSpinnerDropdownMode);
+    }
 
-        spinner.setPromptId(R.string.hello_world);
-        assertEquals(mTargetContext.getString(R.string.hello_world), spinner.getPrompt());
+    private void verifySetPromptId(Spinner spinner) {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        instrumentation.runOnMainSync(() -> spinner.setPromptId(R.string.hello_world));
+        assertEquals(mActivity.getString(R.string.hello_world), spinner.getPrompt());
 
         try {
             spinner.setPromptId(-1);
@@ -165,23 +238,209 @@
         } catch (NotFoundException e) {
             // issue 1695243, not clear what is supposed to happen if promptId is exceptional.
         }
+    }
 
-        // TODO: find the dialog and get its title to assert whether setPromptId() takes effect?
+    public void testSetPromptId() {
+        verifySetPromptId(mSpinnerDialogMode);
+        verifySetPromptId(mSpinnerDropdownMode);
     }
 
     @UiThreadTest
     public void testGetPopupContext() {
-        Theme theme = mTargetContext.getResources().newTheme();
-        Spinner themeSpinner = new Spinner(mTargetContext, null,
+        Theme theme = mActivity.getResources().newTheme();
+        Spinner themeSpinner = new Spinner(mActivity, null,
                 android.R.attr.spinnerStyle, 0, Spinner.MODE_DIALOG, theme);
-        assertNotSame(mTargetContext, themeSpinner.getPopupContext());
+        assertNotSame(mActivity, themeSpinner.getPopupContext());
         assertSame(theme, themeSpinner.getPopupContext().getTheme());
 
         ContextThemeWrapper context = (ContextThemeWrapper)themeSpinner.getPopupContext();
-        assertSame(mTargetContext, context.getBaseContext());
+        assertSame(mActivity, context.getBaseContext());
     }
 
-    public void testOnLayout() {
-        // onLayout() is implementation details, do NOT test
+    private void verifyGravity(Spinner spinner) {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // Note that here we're using a custom layout for the spinner's selected item
+        // that doesn't span the whole width of the parent. That way we're exercising the
+        // relevant path in spinner's layout pass that handles the currently set gravity
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, R.layout.simple_spinner_item_layout);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        instrumentation.runOnMainSync(() -> spinner.setAdapter(adapter));
+
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, spinner, () -> {
+            spinner.setSelection(1);
+            spinner.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
+            spinner.requestLayout();
+        });
+
+        instrumentation.runOnMainSync(() -> spinner.setGravity(Gravity.LEFT));
+        assertEquals(Gravity.LEFT, spinner.getGravity());
+
+        instrumentation.runOnMainSync(() -> spinner.setGravity(Gravity.CENTER_HORIZONTAL));
+        assertEquals(Gravity.CENTER_HORIZONTAL, spinner.getGravity());
+
+        instrumentation.runOnMainSync((() -> spinner.setGravity(Gravity.RIGHT)));
+        assertEquals(Gravity.RIGHT, spinner.getGravity());
+
+        instrumentation.runOnMainSync(() -> spinner.setGravity(Gravity.START));
+        assertEquals(Gravity.START, spinner.getGravity());
+
+        instrumentation.runOnMainSync(() -> spinner.setGravity(Gravity.END));
+        assertEquals(Gravity.END, spinner.getGravity());
+    }
+
+    public void testGravity() {
+        verifyGravity(mSpinnerDialogMode);
+        verifyGravity(mSpinnerDropdownMode);
+    }
+
+    public void testDropDownMetricsDropdownMode() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        instrumentation.runOnMainSync(() -> mSpinnerDropdownMode.setAdapter(adapter));
+
+        final Resources res = mActivity.getResources();
+        final int dropDownWidth = res.getDimensionPixelSize(R.dimen.spinner_dropdown_width);
+        final int dropDownOffsetHorizontal =
+                res.getDimensionPixelSize(R.dimen.spinner_dropdown_offset_h);
+        final int dropDownOffsetVertical =
+                res.getDimensionPixelSize(R.dimen.spinner_dropdown_offset_v);
+
+        instrumentation.runOnMainSync(() -> {
+            mSpinnerDropdownMode.setDropDownWidth(dropDownWidth);
+            mSpinnerDropdownMode.setDropDownHorizontalOffset(dropDownOffsetHorizontal);
+            mSpinnerDropdownMode.setDropDownVerticalOffset(dropDownOffsetVertical);
+        });
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDropdownMode);
+        // Verify that we're showing the popup
+        assertTrue(mSpinnerDropdownMode.isPopupShowing());
+
+        // And test its attributes
+        assertEquals(dropDownWidth, mSpinnerDropdownMode.getDropDownWidth());
+        // TODO: restore when b/28089349 is addressed
+        // assertEquals(dropDownOffsetHorizontal,
+        //      mSpinnerDropdownMode.getDropDownHorizontalOffset());
+        assertEquals(dropDownOffsetVertical, mSpinnerDropdownMode.getDropDownVerticalOffset());
+    }
+
+    public void testDropDownMetricsDialogMode() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        instrumentation.runOnMainSync(() -> mSpinnerDialogMode.setAdapter(adapter));
+
+        final Resources res = mActivity.getResources();
+        final int dropDownWidth = res.getDimensionPixelSize(R.dimen.spinner_dropdown_width);
+        final int dropDownOffsetHorizontal =
+                res.getDimensionPixelSize(R.dimen.spinner_dropdown_offset_h);
+        final int dropDownOffsetVertical =
+                res.getDimensionPixelSize(R.dimen.spinner_dropdown_offset_v);
+
+        instrumentation.runOnMainSync(() -> {
+            // These are all expected to be no-ops
+            mSpinnerDialogMode.setDropDownWidth(dropDownWidth);
+            mSpinnerDialogMode.setDropDownHorizontalOffset(dropDownOffsetHorizontal);
+            mSpinnerDialogMode.setDropDownVerticalOffset(dropDownOffsetVertical);
+        });
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDialogMode);
+        // Verify that we're showing the popup
+        assertTrue(mSpinnerDialogMode.isPopupShowing());
+
+        // And test its attributes. Note that we are not testing the result of getDropDownWidth
+        // for this mode
+        assertEquals(0, mSpinnerDialogMode.getDropDownHorizontalOffset());
+        assertEquals(0, mSpinnerDialogMode.getDropDownVerticalOffset());
+    }
+
+    public void testDropDownBackgroundDropdownMode() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        instrumentation.runOnMainSync(() -> mSpinnerDropdownMode.setAdapter(adapter));
+
+        // Set blue background on the popup
+        instrumentation.runOnMainSync(() ->
+                mSpinnerDropdownMode.setPopupBackgroundResource(R.drawable.blue_fill));
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDropdownMode);
+        // Verify that we're showing the popup
+        assertTrue(mSpinnerDropdownMode.isPopupShowing());
+        // And test its fill
+        Drawable dropDownBackground = mSpinnerDropdownMode.getPopupBackground();
+        TestUtils.assertAllPixelsOfColor("Drop down should be blue", dropDownBackground,
+                dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
+                false, Color.BLUE, 1, true);
+
+        // Dismiss the popup with the emulated back key
+        instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        instrumentation.waitForIdleSync();
+        // Verify that we're not showing the popup
+        assertFalse(mSpinnerDropdownMode.isPopupShowing());
+
+        // Set yellow background on the popup
+        instrumentation.runOnMainSync(() ->
+                mSpinnerDropdownMode.setPopupBackgroundDrawable(
+                        mActivity.getDrawable(R.drawable.yellow_fill)));
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDropdownMode);
+        // Verify that we're showing the popup
+        assertTrue(mSpinnerDropdownMode.isPopupShowing());
+        // And test its fill
+        dropDownBackground = mSpinnerDropdownMode.getPopupBackground();
+        TestUtils.assertAllPixelsOfColor("Drop down should be yellow", dropDownBackground,
+                dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
+                false, Color.YELLOW, 1, true);
+    }
+
+    public void testDropDownBackgroundDialogMode() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        instrumentation.runOnMainSync(() -> mSpinnerDialogMode.setAdapter(adapter));
+
+        // Set blue background on the popup
+        instrumentation.runOnMainSync(() ->
+                mSpinnerDialogMode.setPopupBackgroundResource(R.drawable.blue_fill));
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDialogMode);
+        // Verify that we're showing the popup
+        assertTrue(mSpinnerDialogMode.isPopupShowing());
+        // And test that getPopupBackground returns null
+        assertNull(mSpinnerDialogMode.getPopupBackground());
+
+        // Dismiss the popup with the emulated back key
+        instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        instrumentation.waitForIdleSync();
+        // Verify that we're not showing the popup
+        assertFalse(mSpinnerDialogMode.isPopupShowing());
+
+        // Set yellow background on the popup
+        instrumentation.runOnMainSync(() ->
+                mSpinnerDialogMode.setPopupBackgroundDrawable(
+                        mActivity.getDrawable(R.drawable.yellow_fill)));
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDialogMode);
+        // Verify that we're showing the popup
+        assertTrue(mSpinnerDialogMode.isPopupShowing());
+        // And test that getPopupBackground returns null
+        assertNull(mSpinnerDialogMode.getPopupBackground());
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/SwitchTest.java b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
index 216b17b..ba7066e 100644
--- a/tests/tests/widget/src/android/widget/cts/SwitchTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
@@ -17,22 +17,27 @@
 package android.widget.cts;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.res.ColorStateList;
+import android.cts.util.WidgetTestUtils;
 import android.graphics.Color;
 import android.graphics.PorterDuff.Mode;
-import android.test.ActivityInstrumentationTestCase;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.view.ContextThemeWrapper;
+import android.view.ViewGroup;
 import android.widget.Switch;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
+import android.widget.cts.util.TestUtils;
 
 /**
  * Test {@link Switch}.
  */
 @SmallTest
-public class SwitchTest extends ActivityInstrumentationTestCase<SwitchCtsActivity> {
+public class SwitchTest extends ActivityInstrumentationTestCase2<SwitchCtsActivity> {
     private Activity mActivity;
     private Switch mSwitch;
 
@@ -44,7 +49,10 @@
     protected void setUp() throws Exception {
         super.setUp();
         mActivity = getActivity();
-        mSwitch = (Switch) mActivity.findViewById(R.id.switch_view);
+    }
+
+    private Switch findSwitchById(int id) {
+        return (Switch) mActivity.findViewById(id);
     }
 
     @UiThreadTest
@@ -55,11 +63,16 @@
 
         new Switch(mActivity, null, android.R.attr.switchStyle);
 
+        new Switch(mActivity, null, 0, android.R.style.Widget_Material_CompoundButton_Switch);
+
         new Switch(mActivity, null, 0, android.R.style.Widget_Material_Light_CompoundButton_Switch);
     }
 
     @UiThreadTest
     public void testAccessThumbTint() {
+        mSwitch = findSwitchById(R.id.switch1);
+
+        // These are the default set in layout XML
         assertEquals(Color.WHITE, mSwitch.getThumbTintList().getDefaultColor());
         assertEquals(Mode.SRC_OVER, mSwitch.getThumbTintMode());
 
@@ -73,6 +86,9 @@
 
     @UiThreadTest
     public void testAccessTrackTint() {
+        mSwitch = findSwitchById(R.id.switch1);
+
+        // These are the default set in layout XML
         assertEquals(Color.BLACK, mSwitch.getTrackTintList().getDefaultColor());
         assertEquals(Mode.SRC_ATOP, mSwitch.getTrackTintMode());
 
@@ -83,4 +99,175 @@
         assertSame(colors, mSwitch.getTrackTintList());
         assertEquals(Mode.XOR, mSwitch.getTrackTintMode());
     }
+
+    public void testAccessThumbDrawable() {
+        mSwitch = findSwitchById(R.id.switch2);
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // This is the default set in layout XML
+        Drawable thumbDrawable = mSwitch.getThumbDrawable();
+        TestUtils.assertAllPixelsOfColor("Thumb drawable should be blue", thumbDrawable,
+                thumbDrawable.getIntrinsicWidth(), thumbDrawable.getIntrinsicHeight(), false,
+                Color.BLUE, 1, true);
+
+        // Change thumb drawable to red
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setThumbDrawable(mActivity.getDrawable(R.drawable.icon_red)));
+        thumbDrawable = mSwitch.getThumbDrawable();
+        TestUtils.assertAllPixelsOfColor("Thumb drawable should be red", thumbDrawable,
+                thumbDrawable.getIntrinsicWidth(), thumbDrawable.getIntrinsicHeight(), false,
+                Color.RED, 1, true);
+
+        // Change thumb drawable to green
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setThumbResource(R.drawable.icon_green));
+        thumbDrawable = mSwitch.getThumbDrawable();
+        TestUtils.assertAllPixelsOfColor("Thumb drawable should be green", thumbDrawable,
+                thumbDrawable.getIntrinsicWidth(), thumbDrawable.getIntrinsicHeight(), false,
+                Color.GREEN, 1, true);
+
+        // Now tint the latest (green) thumb drawable with 50% blue SRC_OVER
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch, () -> {
+            mSwitch.setThumbTintList(ColorStateList.valueOf(0x800000FF));
+            mSwitch.setThumbTintMode(Mode.SRC_OVER);
+        });
+        thumbDrawable = mSwitch.getThumbDrawable();
+        TestUtils.assertAllPixelsOfColor("Thumb drawable should be green / blue", thumbDrawable,
+                thumbDrawable.getIntrinsicWidth(), thumbDrawable.getIntrinsicHeight(), false,
+                TestUtils.compositeColors(0x800000FF, Color.GREEN), 1, true);
+    }
+
+    public void testAccessTrackDrawable() {
+        mSwitch = findSwitchById(R.id.switch2);
+        final Instrumentation instrumentation = getInstrumentation();
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+            () -> mSwitch.setTrackTintMode(Mode.DST));
+
+        // This is the default set in layout XML
+        Drawable trackDrawable = mSwitch.getTrackDrawable();
+        Rect trackDrawableBounds = trackDrawable.getBounds();
+        TestUtils.assertAllPixelsOfColor("Track drawable should be 50% red", trackDrawable,
+                trackDrawableBounds.width(), trackDrawableBounds.height(), false,
+                0x80FF0000, 1, true);
+
+        // Change track drawable to blue
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setTrackDrawable(mActivity.getDrawable(R.drawable.blue_fill)));
+        trackDrawable = mSwitch.getTrackDrawable();
+        trackDrawableBounds = trackDrawable.getBounds();
+        TestUtils.assertAllPixelsOfColor("Track drawable should be blue", trackDrawable,
+                trackDrawableBounds.width(), trackDrawableBounds.height(), false,
+                Color.BLUE, 1, true);
+
+        // Change track drawable to green
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setTrackResource(R.drawable.green_fill));
+        trackDrawable = mSwitch.getTrackDrawable();
+        trackDrawableBounds = trackDrawable.getBounds();
+        TestUtils.assertAllPixelsOfColor("Track drawable should be green", trackDrawable,
+                trackDrawableBounds.width(), trackDrawableBounds.height(), false,
+                Color.GREEN, 1, true);
+
+        // Now tint the latest (green) track drawable with 50% blue SRC_OVER
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch, () -> {
+            mSwitch.setTrackTintList(ColorStateList.valueOf(0x800000FF));
+            mSwitch.setTrackTintMode(Mode.SRC_OVER);
+        });
+        trackDrawable = mSwitch.getTrackDrawable();
+        trackDrawableBounds = trackDrawable.getBounds();
+        TestUtils.assertAllPixelsOfColor("Track drawable should be green / blue", trackDrawable,
+                trackDrawableBounds.width(), trackDrawableBounds.height(), false,
+                TestUtils.compositeColors(0x800000FF, Color.GREEN), 1, true);
+    }
+
+    public void testAccessText() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // Run text-related tests on a Holo-themed switch, since under Material themes we
+        // are not showing texts by default.
+        mSwitch = new Switch(new ContextThemeWrapper(mActivity, android.R.style.Theme_Holo_Light));
+        instrumentation.runOnMainSync(
+                () -> ((ViewGroup) mActivity.findViewById(R.id.container)).addView(mSwitch));
+
+        // Set "on" text and verify it
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setTextOn("Text on"));
+        assertEquals("Text on", mSwitch.getTextOn());
+
+        // Set "off" text and verify it
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setTextOff("Text off"));
+        assertEquals("Text off", mSwitch.getTextOff());
+
+        // Turn text display on
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setShowText(true));
+        assertTrue(mSwitch.getShowText());
+
+        // Use custom text appearance. Since we don't have APIs to query this facet of Switch,
+        // just test that it's not crashing.
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setSwitchTextAppearance(mActivity, R.style.TextAppearance_WithColor));
+
+        // Use custom typeface. Since we don't have APIs to query this facet of Switch,
+        // just test that it's not crashing.
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setSwitchTypeface(Typeface.MONOSPACE));
+
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setSwitchTypeface(Typeface.SERIF, Typeface.ITALIC));
+
+        // Set and verify padding between the thumb and the text
+        final int thumbTextPadding = mActivity.getResources().getDimensionPixelSize(
+                R.dimen.switch_thumb_text_padding);
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setThumbTextPadding(thumbTextPadding));
+        assertEquals(thumbTextPadding, mSwitch.getThumbTextPadding());
+
+        // Set and verify padding between the switch and the text
+        final int switchPadding = mActivity.getResources().getDimensionPixelSize(
+                R.dimen.switch_padding);
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setSwitchPadding(switchPadding));
+        assertEquals(switchPadding, mSwitch.getSwitchPadding());
+
+        // Turn text display off
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setShowText(false));
+        assertFalse(mSwitch.getShowText());
+    }
+
+    public void testAccessMinWidth() {
+        mSwitch = findSwitchById(R.id.switch3);
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // Set custom min width on the switch and verify that it's at least that wide
+        final int switchMinWidth = mActivity.getResources().getDimensionPixelSize(
+                R.dimen.switch_min_width);
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setSwitchMinWidth(switchMinWidth));
+        assertEquals(switchMinWidth, mSwitch.getSwitchMinWidth());
+        assertTrue(mSwitch.getWidth() >= switchMinWidth);
+
+        // And set another (larger) min width
+        final int switchMinWidth2 = mActivity.getResources().getDimensionPixelSize(
+                R.dimen.switch_min_width2);
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setSwitchMinWidth(switchMinWidth2));
+        assertEquals(switchMinWidth2, mSwitch.getSwitchMinWidth());
+        assertTrue(mSwitch.getWidth() >= switchMinWidth2);
+    }
+
+    public void testAccessSplitTrack() {
+        mSwitch = findSwitchById(R.id.switch3);
+        final Instrumentation instrumentation = getInstrumentation();
+
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setSplitTrack(true));
+        assertTrue(mSwitch.getSplitTrack());
+
+        WidgetTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+                () -> mSwitch.setSplitTrack(false));
+        assertFalse(mSwitch.getSplitTrack());
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/TabHostCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TabHostCtsActivity.java
index 189dbee..ec0bfa7 100644
--- a/tests/tests/widget/src/android/widget/cts/TabHostCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/TabHostCtsActivity.java
@@ -21,7 +21,6 @@
 import android.view.View;
 import android.widget.TabHost;
 import android.widget.TextView;
-
 import android.widget.cts.R;
 
 /**
diff --git a/tests/tests/widget/src/android/widget/cts/TabHostTest.java b/tests/tests/widget/src/android/widget/cts/TabHostTest.java
index 8756687..b8e0a8a 100644
--- a/tests/tests/widget/src/android/widget/cts/TabHostTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabHostTest.java
@@ -16,6 +16,8 @@
 
 package android.widget.cts;
 
+import static org.mockito.Mockito.*;
+
 import android.app.Activity;
 import android.app.ActivityGroup;
 import android.content.Intent;
@@ -30,8 +32,6 @@
 import android.widget.TabHost.TabSpec;
 import android.widget.TextView;
 
-import static org.mockito.Mockito.*;
-
 /**
  * Test {@link TabHost}.
  */
diff --git a/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java b/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java
index e8825c7..d4d2bf1 100644
--- a/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java
@@ -16,9 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.Instrumentation.ActivityMonitor;
@@ -33,8 +30,9 @@
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TabHost;
-import android.widget.TextView;
 import android.widget.TabHost.TabSpec;
+import android.widget.TextView;
+import android.widget.cts.R;
 
 /**
  * Test {@link TabSpec}.
diff --git a/tests/tests/widget/src/android/widget/cts/TableCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TableCtsActivity.java
index 490d261..ce3fd7e 100644
--- a/tests/tests/widget/src/android/widget/cts/TableCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/TableCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 /**
  * A minimal application for TableLayout test.
diff --git a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
index ccf22d9..e3884cc 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.mockito.Mockito.*;
 
 import android.content.Context;
 import android.content.res.XmlResourceParser;
@@ -25,9 +25,8 @@
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
-import android.view.ViewGroup.OnHierarchyChangeListener;
+import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.RelativeLayout;
@@ -72,21 +71,21 @@
     public void testSetOnHierarchyChangeListener() {
         TableLayout tableLayout = new TableLayout(mContext);
 
-        MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
-        tableLayout.setOnHierarchyChangeListener(listener);
+        ViewGroup.OnHierarchyChangeListener mockHierarchyChangeListener =
+                mock(ViewGroup.OnHierarchyChangeListener.class);
+        tableLayout.setOnHierarchyChangeListener(mockHierarchyChangeListener);
 
-        tableLayout.addView(new TextView(mContext));
-        assertTrue(listener.hasCalledOnChildViewAdded());
+        View toAdd = new TextView(mContext);
+        tableLayout.addView(toAdd);
+        verify(mockHierarchyChangeListener, times(1)).onChildViewAdded(tableLayout, toAdd);
         tableLayout.removeViewAt(0);
-        assertTrue(listener.hasCalledOnChildViewRemoved());
-
-        listener.reset();
+        verify(mockHierarchyChangeListener, times(1)).onChildViewRemoved(tableLayout, toAdd);
+        verifyNoMoreInteractions(mockHierarchyChangeListener);
 
         tableLayout.setOnHierarchyChangeListener(null);
         tableLayout.addView(new TextView(mContext));
-        assertFalse(listener.hasCalledOnChildViewAdded());
         tableLayout.removeViewAt(0);
-        assertFalse(listener.hasCalledOnChildViewRemoved());
+        verifyNoMoreInteractions(mockHierarchyChangeListener);
     }
 
     public void testRequestLayout() {
@@ -456,7 +455,8 @@
         assertNull(child1.getLayoutParams());
         tableLayout.addView(child1, new ViewGroup.LayoutParams(100, 200));
         assertSame(child1, tableLayout.getChildAt(0));
-        assertEquals(100, tableLayout.getChildAt(0).getLayoutParams().width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                tableLayout.getChildAt(0).getLayoutParams().width);
         assertEquals(200, tableLayout.getChildAt(0).getLayoutParams().height);
         assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
 
@@ -467,9 +467,11 @@
         tableLayout.addView(child2, new TableRow.LayoutParams(200, 300, 1));
         assertSame(child1, tableLayout.getChildAt(0));
         assertSame(child2, tableLayout.getChildAt(1));
-        assertEquals(100, tableLayout.getChildAt(0).getLayoutParams().width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                tableLayout.getChildAt(0).getLayoutParams().width);
         assertEquals(200, tableLayout.getChildAt(0).getLayoutParams().height);
-        assertEquals(200, tableLayout.getChildAt(1).getLayoutParams().width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                tableLayout.getChildAt(1).getLayoutParams().width);
         assertEquals(300, tableLayout.getChildAt(1).getLayoutParams().height);
         assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
         assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
@@ -494,7 +496,8 @@
         assertNull(child1.getLayoutParams());
         tableLayout.addView(child1, 0, new ViewGroup.LayoutParams(100, 200));
         assertSame(child1, tableLayout.getChildAt(0));
-        assertEquals(100, tableLayout.getChildAt(0).getLayoutParams().width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                tableLayout.getChildAt(0).getLayoutParams().width);
         assertEquals(200, tableLayout.getChildAt(0).getLayoutParams().height);
         assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
 
@@ -505,9 +508,11 @@
         tableLayout.addView(child2, 0, new TableRow.LayoutParams(200, 300, 1));
         assertSame(child2, tableLayout.getChildAt(0));
         assertSame(child1, tableLayout.getChildAt(1));
-        assertEquals(200, tableLayout.getChildAt(0).getLayoutParams().width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                tableLayout.getChildAt(0).getLayoutParams().width);
         assertEquals(300, tableLayout.getChildAt(0).getLayoutParams().height);
-        assertEquals(100, tableLayout.getChildAt(1).getLayoutParams().width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                tableLayout.getChildAt(1).getLayoutParams().width);
         assertEquals(200, tableLayout.getChildAt(1).getLayoutParams().height);
         assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
         assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
@@ -520,11 +525,14 @@
         assertSame(child2, tableLayout.getChildAt(0));
         assertSame(child1, tableLayout.getChildAt(1));
         assertSame(child3, tableLayout.getChildAt(2));
-        assertEquals(200, tableLayout.getChildAt(0).getLayoutParams().width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                tableLayout.getChildAt(0).getLayoutParams().width);
         assertEquals(300, tableLayout.getChildAt(0).getLayoutParams().height);
-        assertEquals(100, tableLayout.getChildAt(1).getLayoutParams().width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                tableLayout.getChildAt(1).getLayoutParams().width);
         assertEquals(200, tableLayout.getChildAt(1).getLayoutParams().height);
-        assertEquals(300, tableLayout.getChildAt(2).getLayoutParams().width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                tableLayout.getChildAt(2).getLayoutParams().width);
         assertEquals(400, tableLayout.getChildAt(2).getLayoutParams().height);
         assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
         assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
@@ -588,7 +596,7 @@
         LinearLayout.LayoutParams layoutParams = mockTableLayout.generateLayoutParams(
                 new ViewGroup.LayoutParams(200, 300));
         assertNotNull(layoutParams);
-        assertEquals(200, layoutParams.width);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, layoutParams.width);
         assertEquals(300, layoutParams.height);
         assertTrue(layoutParams instanceof TableLayout.LayoutParams);
 
@@ -611,50 +619,6 @@
         mockTableLayout.onMeasure(MeasureSpec.EXACTLY, MeasureSpec.EXACTLY);
     }
 
-    private int dropNegative(int number) {
-        return (number > 0 ? number : 0);
-    }
-
-    private class MockOnHierarchyChangeListener implements OnHierarchyChangeListener {
-        private boolean mCalledOnChildViewAdded = false;
-        private boolean mCalledOnChildViewRemoved = false;
-
-        /*
-         * (non-Javadoc)
-         *
-         * @see
-         * android.view.ViewGroup.OnHierarchyChangeListener#onChildViewAdded
-         * (View, View)
-         */
-        public void onChildViewAdded(View parent, View child) {
-            mCalledOnChildViewAdded = true;
-        }
-
-        /*
-         * (non-Javadoc)
-         *
-         * @see
-         * android.view.ViewGroup.OnHierarchyChangeListener#onChildViewRemoved
-         * (View, View)
-         */
-        public void onChildViewRemoved(View parent, View child) {
-            mCalledOnChildViewRemoved = true;
-        }
-
-        public boolean hasCalledOnChildViewAdded() {
-            return mCalledOnChildViewAdded;
-        }
-
-        public boolean hasCalledOnChildViewRemoved() {
-            return mCalledOnChildViewRemoved;
-        }
-
-        public void reset() {
-            mCalledOnChildViewAdded = false;
-            mCalledOnChildViewRemoved = false;
-        }
-    }
-
     /*
      * Mock class for TableLayout to test protected methods
      */
diff --git a/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
index fbd9f97..41f1816 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
@@ -16,19 +16,19 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.test.InstrumentationTestCase;
 import android.util.AttributeSet;
 import android.util.Xml;
+import android.view.ViewGroup;
 import android.widget.TableLayout;
+import android.widget.cts.R;
 import android.widget.cts.util.XmlUtils;
 
+import org.xmlpull.v1.XmlPullParser;
+
 /**
  * Test {@link TableLayout.LayoutParams}.
  */
@@ -42,28 +42,47 @@
     }
 
     public void testConstructor() {
-        new TableLayout.LayoutParams(mTargetContext, null);
+        // We expect width to be MATCH and height to be WRAP as documented in TableLayout
+        TableLayout.LayoutParams layoutParams = new TableLayout.LayoutParams();
+        assertEquals(TableLayout.LayoutParams.MATCH_PARENT, layoutParams.width);
+        assertEquals(TableLayout.LayoutParams.WRAP_CONTENT, layoutParams.height);
 
-        TableLayout.LayoutParams layoutParams = new TableLayout.LayoutParams(200, 300);
+        // We expect width to be MATCH and height to be WRAP as documented in TableLayout
+        layoutParams = new TableLayout.LayoutParams(mTargetContext, null);
+        assertEquals(TableLayout.LayoutParams.MATCH_PARENT, layoutParams.width);
+        assertEquals(TableLayout.LayoutParams.WRAP_CONTENT, layoutParams.height);
+
+        // We expect width to be MATCH, ignoring what is passed in the constructor
+        layoutParams = new TableLayout.LayoutParams(200, 300);
         assertEquals(TableLayout.LayoutParams.MATCH_PARENT, layoutParams.width);
         assertEquals(300, layoutParams.height);
-        TableLayout.LayoutParams oldParams = layoutParams;
 
-        layoutParams = new TableLayout.LayoutParams(200, 300, 1.2f);
+        // We expect width to be MATCH, ignoring what is passed in the constructor
+        layoutParams = new TableLayout.LayoutParams(250, 350, 1.2f);
         assertEquals(TableLayout.LayoutParams.MATCH_PARENT, layoutParams.width);
-        assertEquals(300, layoutParams.height);
+        assertEquals(350, layoutParams.height);
         assertEquals(1.2f, layoutParams.weight);
-        TableLayout.LayoutParams oldMarginParams = layoutParams;
 
-        new TableLayout.LayoutParams();
-
-        layoutParams = new TableLayout.LayoutParams(oldParams);
+        // We expect width to be MATCH, ignoring what is set on the passed object
+        layoutParams = new TableLayout.LayoutParams(new ViewGroup.LayoutParams(300, 360));
         assertEquals(TableLayout.LayoutParams.MATCH_PARENT, layoutParams.width);
-        assertEquals(300, layoutParams.height);
+        assertEquals(360, layoutParams.height);
 
-        layoutParams = new TableLayout.LayoutParams(oldMarginParams);
+        // We expect width to be MATCH, ignoring what is set on the passed object
+        layoutParams = new TableLayout.LayoutParams(new ViewGroup.MarginLayoutParams(320, 420));
         assertEquals(TableLayout.LayoutParams.MATCH_PARENT, layoutParams.width);
-        assertEquals(300, layoutParams.height);
+        assertEquals(420, layoutParams.height);
+
+        // We expect width to be MATCH as that is copied from the passed object
+        layoutParams = new TableLayout.LayoutParams(new TableLayout.LayoutParams(500, 400));
+        assertEquals(TableLayout.LayoutParams.MATCH_PARENT, layoutParams.width);
+        assertEquals(400, layoutParams.height);
+
+        // We expect width to be MATCH as that is copied from the passed object
+        layoutParams = new TableLayout.LayoutParams(new TableLayout.LayoutParams(550, 650, 1.4f));
+        assertEquals(TableLayout.LayoutParams.MATCH_PARENT, layoutParams.width);
+        assertEquals(650, layoutParams.height);
+        assertEquals(1.4f, layoutParams.weight);
     }
 
     public void testSetBaseAttributes() {
diff --git a/tests/tests/widget/src/android/widget/cts/TableRowTest.java b/tests/tests/widget/src/android/widget/cts/TableRowTest.java
index 2e917f8..42f2a97 100644
--- a/tests/tests/widget/src/android/widget/cts/TableRowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableRowTest.java
@@ -16,6 +16,8 @@
 
 package android.widget.cts;
 
+import static org.mockito.Mockito.*;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -24,18 +26,14 @@
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
-import android.view.ViewGroup.OnHierarchyChangeListener;
+import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 import android.widget.TableLayout;
 import android.widget.TableRow;
 import android.widget.TextView;
 
-import android.widget.cts.R;
-
-
 /**
  * Test {@link TableRow}.
  */
@@ -63,21 +61,21 @@
     public void testSetOnHierarchyChangeListener() {
         TableRow tableRow = new TableRow(mContext);
 
-        MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
-        tableRow.setOnHierarchyChangeListener(listener);
+        ViewGroup.OnHierarchyChangeListener mockHierarchyChangeListener =
+                mock(ViewGroup.OnHierarchyChangeListener.class);
+        tableRow.setOnHierarchyChangeListener(mockHierarchyChangeListener);
 
-        tableRow.addView(new TextView(mContext));
-        assertTrue(listener.hasCalledOnChildViewAdded());
+        View toAdd = new TextView(mContext);
+        tableRow.addView(toAdd);
+        verify(mockHierarchyChangeListener, times(1)).onChildViewAdded(tableRow, toAdd);
         tableRow.removeViewAt(0);
-        assertTrue(listener.hasCalledOnChildViewRemoved());
-
-        listener.reset();
+        verify(mockHierarchyChangeListener, times(1)).onChildViewRemoved(tableRow, toAdd);
+        verifyNoMoreInteractions(mockHierarchyChangeListener);
 
         tableRow.setOnHierarchyChangeListener(null);
         tableRow.addView(new TextView(mContext));
-        assertFalse(listener.hasCalledOnChildViewAdded());
         tableRow.removeViewAt(0);
-        assertFalse(listener.hasCalledOnChildViewRemoved());
+        verifyNoMoreInteractions(mockHierarchyChangeListener);
     }
 
     @UiThreadTest
@@ -189,46 +187,6 @@
         mockTableRow.onMeasure(MeasureSpec.EXACTLY, MeasureSpec.EXACTLY);
     }
 
-    private class MockOnHierarchyChangeListener implements OnHierarchyChangeListener {
-        private boolean mCalledOnChildViewAdded = false;
-        private boolean mCalledOnChildViewRemoved = false;
-
-        /*
-         * (non-Javadoc)
-         *
-         * @see
-         * android.view.ViewGroup.OnHierarchyChangeListener#onChildViewAdded
-         * (View, View)
-         */
-        public void onChildViewAdded(View parent, View child) {
-            mCalledOnChildViewAdded = true;
-        }
-
-        /*
-         * (non-Javadoc)
-         *
-         * @see
-         * android.view.ViewGroup.OnHierarchyChangeListener#onChildViewRemoved
-         * (View, View)
-         */
-        public void onChildViewRemoved(View parent, View child) {
-            mCalledOnChildViewRemoved = true;
-        }
-
-        public boolean hasCalledOnChildViewAdded() {
-            return mCalledOnChildViewAdded;
-        }
-
-        public boolean hasCalledOnChildViewRemoved() {
-            return mCalledOnChildViewRemoved;
-        }
-
-        public void reset() {
-            mCalledOnChildViewAdded = false;
-            mCalledOnChildViewRemoved = false;
-        }
-    }
-
     /*
      * Mock class for TableRow to test protected methods
      */
diff --git a/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
index ce3be70..8e39d75 100644
--- a/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
@@ -16,10 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
@@ -32,8 +28,11 @@
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.TableLayout;
 import android.widget.TableRow;
+import android.widget.cts.R;
 import android.widget.cts.util.XmlUtils;
 
+import org.xmlpull.v1.XmlPullParser;
+
 /**
  * Test {@link TableRow.LayoutParams}.
  */
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TextViewCtsActivity.java
index 31fc486..0580150 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewCtsActivity.java
@@ -16,17 +16,16 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.TextView;
 
 /**
- * A minimal application for TextView test.
+ * A minimal application for {@link TextView} test.
  */
 public class TextViewCtsActivity extends Activity {
     /**
-     * Called with the activity is first created.
+     * Called when the activity is first created.
      */
     @Override
     public void onCreate(Bundle savedInstanceState) {
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewFadingEdgeTest.java b/tests/tests/widget/src/android/widget/cts/TextViewFadingEdgeTest.java
index e627c2b..93cad6d 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewFadingEdgeTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewFadingEdgeTest.java
@@ -16,20 +16,20 @@
 
 package android.widget.cts;
 
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
 import static android.view.Gravity.CENTER;
 import static android.view.Gravity.LEFT;
 import static android.view.Gravity.NO_GRAVITY;
 import static android.view.Gravity.RIGHT;
 import static android.view.View.TEXT_ALIGNMENT_INHERIT;
-import static android.widget.TextView.TEXT_ALIGNMENT_TEXT_START;
 import static android.widget.TextView.TEXT_ALIGNMENT_TEXT_END;
-import static android.widget.TextView.TEXT_ALIGNMENT_VIEW_START;
+import static android.widget.TextView.TEXT_ALIGNMENT_TEXT_START;
 import static android.widget.TextView.TEXT_ALIGNMENT_VIEW_END;
+import static android.widget.TextView.TEXT_ALIGNMENT_VIEW_START;
+
+import android.cts.util.PollingCheck;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
 
 public class TextViewFadingEdgeTest extends ActivityInstrumentationTestCase2<EmptyCtsActivity> {
 
@@ -120,12 +120,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return getActivity().hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(() -> getActivity().hasWindowFocus());
     }
 
     public void testFadingEdge() {
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 9f611ad..a4a7897 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -16,17 +16,22 @@
 
 package android.widget.cts;
 
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.Instrumentation.ActivityMonitor;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
-import android.cts.util.KeyEventUtil;
+import android.cts.util.CtsTouchUtils;
+import android.cts.util.CtsKeyEventUtil;
 import android.cts.util.PollingCheck;
 import android.cts.util.WidgetTestUtils;
-import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
@@ -39,10 +44,13 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.LocaleList;
+import android.os.Looper;
 import android.os.Parcelable;
+import android.os.ResultReceiver;
+import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
 import android.test.UiThreadTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -73,6 +81,7 @@
 import android.text.method.TextKeyListener.Capitalize;
 import android.text.method.TimeKeyListener;
 import android.text.method.TransformationMethod;
+import android.text.style.ClickableSpan;
 import android.text.style.ImageSpan;
 import android.text.style.URLSpan;
 import android.text.style.UnderlineSpan;
@@ -83,27 +92,32 @@
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.Gravity;
+import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.Menu;
-import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.view.View;
-import android.view.View.OnCreateContextMenuListener;
-import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
+import android.widget.ScrollView;
 import android.widget.Scroller;
 import android.widget.TextView;
 import android.widget.TextView.BufferType;
-import android.widget.TextView.OnEditorActionListener;
+import android.widget.cts.util.TestUtils;
 
+import org.mockito.invocation.InvocationOnMock;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
@@ -124,7 +138,7 @@
             + "this text, I would love to see the kind of devices you guys now use!";
     private static final long TIMEOUT = 5000;
     private CharSequence mTransformedText;
-    private KeyEventUtil mKeyEventUtil;
+    private Handler mHandler = new Handler(Looper.getMainLooper());
 
     public TextViewTest() {
         super("android.widget.cts", TextViewCtsActivity.class);
@@ -134,28 +148,27 @@
     protected void setUp() throws Exception {
         super.setUp();
         mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
         mInstrumentation = getInstrumentation();
-        mKeyEventUtil = new KeyEventUtil(mInstrumentation);
     }
 
     /**
-     * Promotes the TextView to editable and places focus in it to allow simulated typing.
+     * Promotes the TextView to editable and places focus in it to allow simulated typing. Used in
+     * test methods annotated with {@link android.test.UiThreadTest}.
      */
     private void initTextViewForTyping() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = findTextView(R.id.textview_text);
-                mTextView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
-                mTextView.setText("", BufferType.EDITABLE);
-                mTextView.requestFocus();
-            }
-        });
+        mTextView = findTextView(R.id.textview_text);
+        mTextView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
+        mTextView.setText("", BufferType.EDITABLE);
+        mTextView.requestFocus();
+    }
+
+    /**
+     * Used in test methods that can not entirely be run on the UiThread (e.g: tests that need to
+     * emulate touches and/or key presses).
+     */
+    private void initTextViewForTypingOnUiThread() {
+        mActivity.runOnUiThread(this::initTextViewForTyping);
         mInstrumentation.waitForIdleSync();
     }
 
@@ -164,7 +177,15 @@
 
         new TextView(mActivity, null);
 
-        new TextView(mActivity, null, 0);
+        new TextView(mActivity, null, android.R.attr.textViewStyle);
+
+        new TextView(mActivity, null, 0, android.R.style.Widget_DeviceDefault_TextView);
+
+        new TextView(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Light_TextView);
+
+        new TextView(mActivity, null, 0, android.R.style.Widget_Material_TextView);
+
+        new TextView(mActivity, null, 0, android.R.style.Widget_Material_Light_TextView);
     }
 
     @UiThreadTest
@@ -188,11 +209,9 @@
     }
 
     public void testGetLayout() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = findTextView(R.id.textview_text);
-                mTextView.setGravity(Gravity.CENTER);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView = findTextView(R.id.textview_text);
+            mTextView.setGravity(Gravity.CENTER);
         });
         mInstrumentation.waitForIdleSync();
         assertNotNull(mTextView.getLayout());
@@ -211,32 +230,20 @@
     }
 
     public void testAccessKeyListener() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = findTextView(R.id.textview_text);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView = findTextView(R.id.textview_text));
         mInstrumentation.waitForIdleSync();
 
         assertNull(mTextView.getKeyListener());
 
         final KeyListener digitsKeyListener = DigitsKeyListener.getInstance();
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(digitsKeyListener);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setKeyListener(digitsKeyListener));
         mInstrumentation.waitForIdleSync();
         assertSame(digitsKeyListener, mTextView.getKeyListener());
 
         final QwertyKeyListener qwertyKeyListener
                 = QwertyKeyListener.getInstance(false, Capitalize.NONE);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(qwertyKeyListener);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setKeyListener(qwertyKeyListener));
         mInstrumentation.waitForIdleSync();
         assertSame(qwertyKeyListener, mTextView.getKeyListener());
     }
@@ -249,42 +256,38 @@
         final int selectionStart = 10;
         final int selectionEnd = LONG_TEXT.length();
         final MovementMethod movementMethod = ArrowKeyMovementMethod.getInstance();
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = findTextView(R.id.textview_text);
-                mTextView.setMovementMethod(movementMethod);
-                mTextView.setText(LONG_TEXT, BufferType.EDITABLE);
-                Selection.setSelection((Editable) mTextView.getText(),
-                        selectionStart, selectionEnd);
-                mTextView.requestFocus();
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView = findTextView(R.id.textview_text);
+            mTextView.setMovementMethod(movementMethod);
+            mTextView.setText(LONG_TEXT, BufferType.EDITABLE);
+            Selection.setSelection((Editable) mTextView.getText(),
+                    selectionStart, selectionEnd);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
         assertSame(movementMethod, mTextView.getMovementMethod());
         assertEquals(selectionStart, Selection.getSelectionStart(mTextView.getText()));
         assertEquals(selectionEnd, Selection.getSelectionEnd(mTextView.getText()));
-        sendKeys(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_ALT_LEFT,
-                KeyEvent.KEYCODE_DPAD_UP);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_SHIFT_LEFT,
+                KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_DPAD_UP);
         // the selection has been removed.
         assertEquals(selectionStart, Selection.getSelectionStart(mTextView.getText()));
         assertEquals(selectionStart, Selection.getSelectionEnd(mTextView.getText()));
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMovementMethod(null);
-                Selection.setSelection((Editable) mTextView.getText(),
-                        selectionStart, selectionEnd);
-                mTextView.requestFocus();
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setMovementMethod(null);
+            Selection.setSelection((Editable) mTextView.getText(),
+                    selectionStart, selectionEnd);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
         assertNull(mTextView.getMovementMethod());
         assertEquals(selectionStart, Selection.getSelectionStart(mTextView.getText()));
         assertEquals(selectionEnd, Selection.getSelectionEnd(mTextView.getText()));
-        sendKeys(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_ALT_LEFT,
-                KeyEvent.KEYCODE_DPAD_UP);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_SHIFT_LEFT,
+                KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_DPAD_UP);
         // the selection will not be changed.
         assertEquals(selectionStart, Selection.getSelectionStart(mTextView.getText()));
         assertEquals(selectionEnd, Selection.getSelectionEnd(mTextView.getText()));
@@ -352,11 +355,9 @@
         mTextView = findTextView(R.id.textview_text);
         final CharSequence text1 =
                 new SpannableString("URL: http://www.google.com. mailto: account@gmail.com");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setAutoLinkMask(Linkify.ALL);
-                mTextView.setText(text1, BufferType.EDITABLE);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setAutoLinkMask(Linkify.ALL);
+            mTextView.setText(text1, BufferType.EDITABLE);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(Linkify.ALL, mTextView.getAutoLinkMask());
@@ -370,11 +371,9 @@
 
         final CharSequence text2 =
             new SpannableString("name: Jack. tel: +41 44 800 8999");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setAutoLinkMask(Linkify.PHONE_NUMBERS);
-                mTextView.setText(text2, BufferType.EDITABLE);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setAutoLinkMask(Linkify.PHONE_NUMBERS);
+            mTextView.setText(text2, BufferType.EDITABLE);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(Linkify.PHONE_NUMBERS, mTextView.getAutoLinkMask());
@@ -470,38 +469,78 @@
         }
     }
 
-    public void testSetHighlightColor() {
-        mTextView = new TextView(mActivity);
+    public void testAccessHighlightColor() {
+        final TextView textView = (TextView) mActivity.findViewById(R.id.textview_text);
 
-        mTextView.setHighlightColor(0x00ff00ff);
+        mActivity.runOnUiThread(() -> {
+            textView.setTextIsSelectable(true);
+            textView.setText("abcd", BufferType.EDITABLE);
+            textView.setHighlightColor(Color.BLUE);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(textView.isTextSelectable());
+        assertEquals(Color.BLUE, textView.getHighlightColor());
+
+        // Long click on the text selects all text and shows selection handlers. The view has an
+        // attribute layout_width="wrap_content", so clicked location (the center of the view)
+        // should be on the text.
+        CtsTouchUtils.emulateLongClick(mInstrumentation, textView);
+
+        // At this point the entire content of our TextView should be selected and highlighted
+        // with blue. Now change the highlight to red while the selection is still on.
+        mActivity.runOnUiThread(() -> textView.setHighlightColor(Color.RED));
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(Color.RED, textView.getHighlightColor());
+        assertTrue(TextUtils.equals("abcd", textView.getText()));
+
+        // Remove the selection
+        mActivity.runOnUiThread(() -> Selection.removeSelection((Spannable) textView.getText()));
+        mInstrumentation.waitForIdleSync();
+
+        // And switch highlight to green after the selection has been removed
+        mActivity.runOnUiThread(() -> textView.setHighlightColor(Color.GREEN));
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(Color.GREEN, textView.getHighlightColor());
+        assertTrue(TextUtils.equals("abcd", textView.getText()));
     }
 
+    @MediumTest
     public void testSetShadowLayer() {
-        MockTextView textView = new MockTextView(mActivity);
+        // test values
+        final MockTextView mockTextView = new MockTextView(mActivity);
+
+        mockTextView.setShadowLayer(1.0f, 0.3f, 0.4f, Color.CYAN);
+        assertEquals(Color.CYAN, mockTextView.getShadowColor());
+        assertEquals(0.3f, mockTextView.getShadowDx());
+        assertEquals(0.4f, mockTextView.getShadowDy());
+        assertEquals(1.0f, mockTextView.getShadowRadius());
 
         // shadow is placed to the left and below the text
-        textView.setShadowLayer(1.0f, 0.3f, 0.3f, Color.CYAN);
-        assertTrue(textView.isPaddingOffsetRequired());
-        assertEquals(0, textView.getLeftPaddingOffset());
-        assertEquals(0, textView.getTopPaddingOffset());
-        assertEquals(1, textView.getRightPaddingOffset());
-        assertEquals(1, textView.getBottomPaddingOffset());
+        mockTextView.setShadowLayer(1.0f, 0.3f, 0.3f, Color.CYAN);
+        assertTrue(mockTextView.isPaddingOffsetRequired());
+        assertEquals(0, mockTextView.getLeftPaddingOffset());
+        assertEquals(0, mockTextView.getTopPaddingOffset());
+        assertEquals(1, mockTextView.getRightPaddingOffset());
+        assertEquals(1, mockTextView.getBottomPaddingOffset());
 
         // shadow is placed to the right and above the text
-        textView.setShadowLayer(1.0f, -0.8f, -0.8f, Color.CYAN);
-        assertTrue(textView.isPaddingOffsetRequired());
-        assertEquals(-1, textView.getLeftPaddingOffset());
-        assertEquals(-1, textView.getTopPaddingOffset());
-        assertEquals(0, textView.getRightPaddingOffset());
-        assertEquals(0, textView.getBottomPaddingOffset());
+        mockTextView.setShadowLayer(1.0f, -0.8f, -0.8f, Color.CYAN);
+        assertTrue(mockTextView.isPaddingOffsetRequired());
+        assertEquals(-1, mockTextView.getLeftPaddingOffset());
+        assertEquals(-1, mockTextView.getTopPaddingOffset());
+        assertEquals(0, mockTextView.getRightPaddingOffset());
+        assertEquals(0, mockTextView.getBottomPaddingOffset());
 
         // no shadow
-        textView.setShadowLayer(0.0f, 0.0f, 0.0f, Color.CYAN);
-        assertFalse(textView.isPaddingOffsetRequired());
-        assertEquals(0, textView.getLeftPaddingOffset());
-        assertEquals(0, textView.getTopPaddingOffset());
-        assertEquals(0, textView.getRightPaddingOffset());
-        assertEquals(0, textView.getBottomPaddingOffset());
+        mockTextView.setShadowLayer(0.0f, 0.0f, 0.0f, Color.CYAN);
+        assertFalse(mockTextView.isPaddingOffsetRequired());
+        assertEquals(0, mockTextView.getLeftPaddingOffset());
+        assertEquals(0, mockTextView.getTopPaddingOffset());
+        assertEquals(0, mockTextView.getRightPaddingOffset());
+        assertEquals(0, mockTextView.getBottomPaddingOffset());
     }
 
     @UiThreadTest
@@ -675,114 +714,199 @@
                 mTextView.getPaintFlags());
     }
 
-    public void testHeightAndWidth() {
+    @MediumTest
+    public void testHeight() {
         mTextView = findTextView(R.id.textview_text);
-        int originalWidth = mTextView.getWidth();
-        setWidth(mTextView.getWidth() >> 3);
-        int originalHeight = mTextView.getHeight();
+        final int originalHeight = mTextView.getHeight();
 
-        setMaxHeight(originalHeight + 1);
+        // test setMaxHeight
+        int newHeight = originalHeight + 1;
+        setMaxHeight(newHeight);
         assertEquals(originalHeight, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMaxHeight());
 
-        setMaxHeight(originalHeight - 1);
-        assertEquals(originalHeight - 1, mTextView.getHeight());
+        newHeight = originalHeight - 1;
+        setMaxHeight(newHeight);
+        assertEquals(newHeight, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMaxHeight());
 
-        setMaxHeight(-1);
+        newHeight = -1;
+        setMaxHeight(newHeight);
         assertEquals(0, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMaxHeight());
 
-        setMaxHeight(Integer.MAX_VALUE);
+        newHeight = Integer.MAX_VALUE;
+        setMaxHeight(newHeight);
         assertEquals(originalHeight, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMaxHeight());
 
-        setMinHeight(originalHeight + 1);
-        assertEquals(originalHeight + 1, mTextView.getHeight());
+        // test setMinHeight
+        newHeight = originalHeight + 1;
+        setMinHeight(newHeight);
+        assertEquals(newHeight, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMinHeight());
 
-        setMinHeight(originalHeight - 1);
+        newHeight = originalHeight - 1;
+        setMinHeight(newHeight);
         assertEquals(originalHeight, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMinHeight());
 
-        setMinHeight(-1);
+        newHeight = -1;
+        setMinHeight(newHeight);
         assertEquals(originalHeight, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMinHeight());
 
+        // reset min and max height
         setMinHeight(0);
         setMaxHeight(Integer.MAX_VALUE);
 
-        setHeight(originalHeight + 1);
-        assertEquals(originalHeight + 1, mTextView.getHeight());
+        // test setHeight
+        newHeight = originalHeight + 1;
+        setHeight(newHeight);
+        assertEquals(newHeight, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMaxHeight());
+        assertEquals(newHeight, mTextView.getMinHeight());
 
-        setHeight(originalHeight - 1);
-        assertEquals(originalHeight - 1, mTextView.getHeight());
+        newHeight = originalHeight - 1;
+        setHeight(newHeight);
+        assertEquals(newHeight, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMaxHeight());
+        assertEquals(newHeight, mTextView.getMinHeight());
 
-        setHeight(-1);
+        newHeight = -1;
+        setHeight(newHeight);
         assertEquals(0, mTextView.getHeight());
+        assertEquals(newHeight, mTextView.getMaxHeight());
+        assertEquals(newHeight, mTextView.getMinHeight());
 
         setHeight(originalHeight);
         assertEquals(originalHeight, mTextView.getHeight());
+        assertEquals(originalHeight, mTextView.getMaxHeight());
+        assertEquals(originalHeight, mTextView.getMinHeight());
 
-        assertEquals(originalWidth >> 3, mTextView.getWidth());
+        // setting max/min lines should cause getMaxHeight/getMinHeight to return -1
+        setMaxLines(2);
+        assertEquals("Setting maxLines should return -1 fir maxHeight",
+                -1, mTextView.getMaxHeight());
 
-        // Min Width
-        setMinWidth(originalWidth + 1);
-        assertEquals(1, mTextView.getLineCount());
-        assertEquals(originalWidth + 1, mTextView.getWidth());
-
-        setMinWidth(originalWidth - 1);
-        assertEquals(2, mTextView.getLineCount());
-        assertEquals(originalWidth - 1, mTextView.getWidth());
-
-        // Width
-        setWidth(originalWidth + 1);
-        assertEquals(1, mTextView.getLineCount());
-        assertEquals(originalWidth + 1, mTextView.getWidth());
-
-        setWidth(originalWidth - 1);
-        assertEquals(2, mTextView.getLineCount());
-        assertEquals(originalWidth - 1, mTextView.getWidth());
+        setMinLines(1);
+        assertEquals("Setting minLines should return -1 for minHeight",
+                -1, mTextView.getMinHeight());
     }
 
+    @MediumTest
+    public void testWidth() {
+        mTextView = findTextView(R.id.textview_text);
+        int originalWidth = mTextView.getWidth();
+
+        int newWidth = mTextView.getWidth() / 8;
+        setWidth(newWidth);
+        assertEquals(newWidth, mTextView.getWidth());
+        assertEquals(newWidth, mTextView.getMaxWidth());
+        assertEquals(newWidth, mTextView.getMinWidth());
+
+        // Min Width
+        newWidth = originalWidth + 1;
+        setMinWidth(newWidth);
+        assertEquals(1, mTextView.getLineCount());
+        assertEquals(newWidth, mTextView.getWidth());
+        assertEquals(newWidth, mTextView.getMinWidth());
+
+        newWidth = originalWidth - 1;
+        setMinWidth(originalWidth - 1);
+        assertEquals(2, mTextView.getLineCount());
+        assertEquals(newWidth, mTextView.getWidth());
+        assertEquals(newWidth, mTextView.getMinWidth());
+
+        // Width
+        newWidth = originalWidth + 1;
+        setWidth(newWidth);
+        assertEquals(1, mTextView.getLineCount());
+        assertEquals(newWidth, mTextView.getWidth());
+        assertEquals(newWidth, mTextView.getMaxWidth());
+        assertEquals(newWidth, mTextView.getMinWidth());
+
+        newWidth = originalWidth - 1;
+        setWidth(newWidth);
+        assertEquals(2, mTextView.getLineCount());
+        assertEquals(newWidth, mTextView.getWidth());
+        assertEquals(newWidth, mTextView.getMaxWidth());
+        assertEquals(newWidth, mTextView.getMinWidth());
+
+        // setting ems should cause getMaxWidth/getMinWidth to return -1
+        setEms(1);
+        assertEquals("Setting ems should return -1 for maxWidth", -1, mTextView.getMaxWidth());
+        assertEquals("Setting ems should return -1 for maxWidth", -1, mTextView.getMinWidth());
+    }
+
+    @MediumTest
     public void testSetMinEms() {
         mTextView = findTextView(R.id.textview_text);
         assertEquals(1, mTextView.getLineCount());
 
-        int originalWidth = mTextView.getWidth();
-        int originalEms = originalWidth / mTextView.getLineHeight();
+        final int originalWidth = mTextView.getWidth();
+        final int originalEms = originalWidth / mTextView.getLineHeight();
 
         setMinEms(originalEms + 1);
         assertEquals((originalEms + 1) * mTextView.getLineHeight(), mTextView.getWidth());
+        assertEquals(-1, mTextView.getMinWidth());
+        assertEquals(originalEms + 1, mTextView.getMinEms());
 
         setMinEms(originalEms - 1);
         assertEquals(originalWidth, mTextView.getWidth());
+        assertEquals(-1, mTextView.getMinWidth());
+        assertEquals(originalEms - 1, mTextView.getMinEms());
+
+        setMinWidth(1);
+        assertEquals(-1, mTextView.getMinEms());
     }
 
+    @MediumTest
     public void testSetMaxEms() {
         mTextView = findTextView(R.id.textview_text);
         assertEquals(1, mTextView.getLineCount());
-        int originalWidth = mTextView.getWidth();
-        int originalEms = originalWidth / mTextView.getLineHeight();
+
+        final int originalWidth = mTextView.getWidth();
+        final int originalEms = originalWidth / mTextView.getLineHeight();
 
         setMaxEms(originalEms + 1);
         assertEquals(1, mTextView.getLineCount());
         assertEquals(originalWidth, mTextView.getWidth());
+        assertEquals(-1, mTextView.getMaxWidth());
+        assertEquals(originalEms + 1, mTextView.getMaxEms());
 
         setMaxEms(originalEms - 1);
         assertTrue(1 < mTextView.getLineCount());
-        assertEquals((originalEms - 1) * mTextView.getLineHeight(),
-                mTextView.getWidth());
+        assertEquals((originalEms - 1) * mTextView.getLineHeight(), mTextView.getWidth());
+        assertEquals(-1, mTextView.getMaxWidth());
+        assertEquals(originalEms - 1, mTextView.getMaxEms());
+
+        setMaxWidth(originalWidth);
+        assertEquals(-1, mTextView.getMaxEms());
     }
 
+    @MediumTest
     public void testSetEms() {
         mTextView = findTextView(R.id.textview_text);
         assertEquals("check height", 1, mTextView.getLineCount());
-        int originalWidth = mTextView.getWidth();
-        int originalEms = originalWidth / mTextView.getLineHeight();
+        final int originalWidth = mTextView.getWidth();
+        final int originalEms = originalWidth / mTextView.getLineHeight();
 
         setEms(originalEms + 1);
         assertEquals(1, mTextView.getLineCount());
-        assertEquals((originalEms + 1) * mTextView.getLineHeight(),
-                mTextView.getWidth());
+        assertEquals((originalEms + 1) * mTextView.getLineHeight(), mTextView.getWidth());
+        assertEquals(-1, mTextView.getMinWidth());
+        assertEquals(-1, mTextView.getMaxWidth());
+        assertEquals(originalEms + 1, mTextView.getMinEms());
+        assertEquals(originalEms + 1, mTextView.getMaxEms());
 
         setEms(originalEms - 1);
         assertTrue((1 < mTextView.getLineCount()));
-        assertEquals((originalEms - 1) * mTextView.getLineHeight(),
-                mTextView.getWidth());
+        assertEquals((originalEms - 1) * mTextView.getLineHeight(), mTextView.getWidth());
+        assertEquals(-1, mTextView.getMinWidth());
+        assertEquals(-1, mTextView.getMaxWidth());
+        assertEquals(originalEms - 1, mTextView.getMinEms());
+        assertEquals(originalEms - 1, mTextView.getMaxEms());
     }
 
     public void testSetLineSpacing() {
@@ -830,31 +954,21 @@
     public void testSetElegantLineHeight() {
         mTextView = findTextView(R.id.textview_text);
         assertFalse(mTextView.getPaint().isElegantTextHeight());
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setWidth(mTextView.getWidth() / 3);
-                mTextView.setPadding(1, 2, 3, 4);
-                mTextView.setGravity(Gravity.BOTTOM);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setWidth(mTextView.getWidth() / 3);
+            mTextView.setPadding(1, 2, 3, 4);
+            mTextView.setGravity(Gravity.BOTTOM);
         });
         mInstrumentation.waitForIdleSync();
 
         int oldHeight = mTextView.getHeight();
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setElegantTextHeight(true);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setElegantTextHeight(true));
         mInstrumentation.waitForIdleSync();
 
         assertTrue(mTextView.getPaint().isElegantTextHeight());
         assertTrue(mTextView.getHeight() > oldHeight);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setElegantTextHeight(false);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setElegantTextHeight(false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mTextView.getPaint().isElegantTextHeight());
         assertTrue(mTextView.getHeight() == oldHeight);
@@ -880,11 +994,7 @@
         assertFalse(mTextView.getFreezesText());
 
         final CharSequence text = "Hello, TextView.";
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(text);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setText(text));
         mInstrumentation.waitForIdleSync();
 
         final URLSpan urlSpan = new URLSpan("ctstest://TextView/test");
@@ -893,12 +1003,10 @@
         ActivityMonitor am = instrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
                 null, false);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                Uri uri = Uri.parse(urlSpan.getURL());
-                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-                mActivity.startActivity(intent);
-            }
+        mActivity.runOnUiThread(() -> {
+            Uri uri = Uri.parse(urlSpan.getURL());
+            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+            mActivity.startActivity(intent);
         });
 
         Activity newActivity = am.waitForActivityWithTimeout(TIMEOUT);
@@ -913,22 +1021,16 @@
         mTextView.setFreezesText(true);
         assertTrue(mTextView.getFreezesText());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(text);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setText(text));
         mInstrumentation.waitForIdleSync();
         // TODO: How to simulate the TextView in frozen icicles.
         am = instrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
                 null, false);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                Uri uri = Uri.parse(urlSpan.getURL());
-                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-                mActivity.startActivity(intent);
-            }
+        mActivity.runOnUiThread(() -> {
+            Uri uri = Uri.parse(urlSpan.getURL());
+            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+            mActivity.startActivity(intent);
         });
 
         Activity oldActivity = newActivity;
@@ -949,31 +1051,30 @@
     public void testSetEditableFactory() {
         mTextView = new TextView(mActivity);
         String text = "sample";
-        MockEditableFactory factory = new MockEditableFactory();
-        mTextView.setEditableFactory(factory);
 
-        factory.reset();
+        final Editable.Factory mockEditableFactory = spy(new Editable.Factory());
+        doCallRealMethod().when(mockEditableFactory).newEditable(any(CharSequence.class));
+        mTextView.setEditableFactory(mockEditableFactory);
+
         mTextView.setText(text);
-        assertFalse(factory.hasCalledNewEditable());
+        verify(mockEditableFactory, never()).newEditable(any(CharSequence.class));
 
-        factory.reset();
+        reset(mockEditableFactory);
         mTextView.setText(text, BufferType.SPANNABLE);
-        assertFalse(factory.hasCalledNewEditable());
+        verify(mockEditableFactory, never()).newEditable(any(CharSequence.class));
 
-        factory.reset();
+        reset(mockEditableFactory);
         mTextView.setText(text, BufferType.NORMAL);
-        assertFalse(factory.hasCalledNewEditable());
+        verify(mockEditableFactory, never()).newEditable(any(CharSequence.class));
 
-        factory.reset();
+        reset(mockEditableFactory);
         mTextView.setText(text, BufferType.EDITABLE);
-        assertTrue(factory.hasCalledNewEditable());
-        assertEquals(text, factory.getSource());
+        verify(mockEditableFactory, times(1)).newEditable(text);
 
         mTextView.setKeyListener(DigitsKeyListener.getInstance());
-        factory.reset();
+        reset(mockEditableFactory);
         mTextView.setText(text, BufferType.EDITABLE);
-        assertTrue(factory.hasCalledNewEditable());
-        assertEquals(text, factory.getSource());
+        verify(mockEditableFactory, times(1)).newEditable(text);
 
         try {
             mTextView.setEditableFactory(null);
@@ -985,31 +1086,30 @@
     public void testSetSpannableFactory() {
         mTextView = new TextView(mActivity);
         String text = "sample";
-        MockSpannableFactory factory = new MockSpannableFactory();
-        mTextView.setSpannableFactory(factory);
 
-        factory.reset();
+        final Spannable.Factory mockSpannableFactory = spy(new Spannable.Factory());
+        doCallRealMethod().when(mockSpannableFactory).newSpannable(any(CharSequence.class));
+        mTextView.setSpannableFactory(mockSpannableFactory);
+
         mTextView.setText(text);
-        assertFalse(factory.hasCalledNewSpannable());
+        verify(mockSpannableFactory, never()).newSpannable(any(CharSequence.class));
 
-        factory.reset();
+        reset(mockSpannableFactory);
         mTextView.setText(text, BufferType.EDITABLE);
-        assertFalse(factory.hasCalledNewSpannable());
+        verify(mockSpannableFactory, never()).newSpannable(any(CharSequence.class));
 
-        factory.reset();
+        reset(mockSpannableFactory);
         mTextView.setText(text, BufferType.NORMAL);
-        assertFalse(factory.hasCalledNewSpannable());
+        verify(mockSpannableFactory, never()).newSpannable(any(CharSequence.class));
 
-        factory.reset();
+        reset(mockSpannableFactory);
         mTextView.setText(text, BufferType.SPANNABLE);
-        assertTrue(factory.hasCalledNewSpannable());
-        assertEquals(text, factory.getSource());
+        verify(mockSpannableFactory, times(1)).newSpannable(text);
 
         mTextView.setMovementMethod(LinkMovementMethod.getInstance());
-        factory.reset();
+        reset(mockSpannableFactory);
         mTextView.setText(text, BufferType.NORMAL);
-        assertTrue(factory.hasCalledNewSpannable());
-        assertEquals(text, factory.getSource());
+        verify(mockSpannableFactory, times(1)).newSpannable(text);
 
         try {
             mTextView.setSpannableFactory(null);
@@ -1325,12 +1425,7 @@
                 ViewGroup.LayoutParams.WRAP_CONTENT);
         layout.addView(textView, layoutParams);
         layout.setLayoutParams(layoutParams);
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setContentView(layout);
-            }
-        });
+        mActivity.runOnUiThread(() -> getActivity().setContentView(layout));
         getInstrumentation().waitForIdleSync();
 
         // measure height of text with no span
@@ -1343,12 +1438,7 @@
         drawable.setBounds(0, 0, spanHeight, spanHeight);
         ImageSpan span = new ImageSpan(drawable);
         text.setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                textView.setText(text);
-            }
-        });
+        mActivity.runOnUiThread(() -> textView.setText(text));
         mInstrumentation.waitForIdleSync();
 
         // measure height with span
@@ -1358,12 +1448,7 @@
 
         // remove the span
         text.removeSpan(span);
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                textView.setText(text);
-            }
-        });
+        mActivity.runOnUiThread(() -> textView.setText(text));
         mInstrumentation.waitForIdleSync();
 
         final int heightAfterRemoveSpan = textView.getHeight();
@@ -1372,98 +1457,88 @@
     }
 
     public void testRemoveSelectionWithSelectionHandles() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mTextView.setTextIsSelectable(true);
-                mTextView.setText("abcd", BufferType.EDITABLE);
-            }
+        assertFalse(mTextView.isTextSelectable());
+        mActivity.runOnUiThread(() -> {
+            mTextView.setTextIsSelectable(true);
+            mTextView.setText("abcd", BufferType.EDITABLE);
         });
         mInstrumentation.waitForIdleSync();
+        assertTrue(mTextView.isTextSelectable());
 
         // Long click on the text selects all text and shows selection handlers. The view has an
         // attribute layout_width="wrap_content", so clicked location (the center of the view)
         // should be on the text.
-        TouchUtils.longClickView(this, mTextView);
+        CtsTouchUtils.emulateLongClick(mInstrumentation, mTextView);
 
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Selection.removeSelection((Spannable) mTextView.getText());
-            }
-        });
-
-        // Make sure that a crash doesn't happen with {@link Selection#removeSelection}.
+        mActivity.runOnUiThread(() -> Selection.removeSelection((Spannable) mTextView.getText()));
         mInstrumentation.waitForIdleSync();
+
+        assertTrue(TextUtils.equals("abcd", mTextView.getText()));
     }
 
     public void testUndo_insert() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Type some text.
-        mKeyEventUtil.sendString(mTextView, "abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Precondition: The cursor is at the end of the text.
-                assertEquals(3, mTextView.getSelectionStart());
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivity.runOnUiThread(() -> {
+            // Precondition: The cursor is at the end of the text.
+            assertEquals(3, mTextView.getSelectionStart());
 
-                // Undo removes the typed string in one step.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
-                assertEquals(0, mTextView.getSelectionStart());
+            // Undo removes the typed string in one step.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
+            assertEquals(0, mTextView.getSelectionStart());
 
-                // Redo restores the text and cursor position.
-                mTextView.onTextContextMenuItem(android.R.id.redo);
-                assertEquals("abc", mTextView.getText().toString());
-                assertEquals(3, mTextView.getSelectionStart());
+            // Redo restores the text and cursor position.
+            mTextView.onTextContextMenuItem(android.R.id.redo);
+            assertEquals("abc", mTextView.getText().toString());
+            assertEquals(3, mTextView.getSelectionStart());
 
-                // Undoing the redo clears the text again.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
+            // Undoing the redo clears the text again.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
 
-                // Undo when the undo stack is empty does nothing.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
-            }
+            // Undo when the undo stack is empty does nothing.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
         });
         mInstrumentation.waitForIdleSync();
     }
 
     public void testUndo_delete() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Simulate deleting text and undoing it.
-        mKeyEventUtil.sendString(mTextView, "xyz");
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL,
-                KeyEvent.KEYCODE_DEL);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Precondition: The text was actually deleted.
-                assertEquals("", mTextView.getText().toString());
-                assertEquals(0, mTextView.getSelectionStart());
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "xyz");
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL,
+                KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(() -> {
+            // Precondition: The text was actually deleted.
+            assertEquals("", mTextView.getText().toString());
+            assertEquals(0, mTextView.getSelectionStart());
 
-                // Undo restores the typed string and cursor position in one step.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("xyz", mTextView.getText().toString());
-                assertEquals(3, mTextView.getSelectionStart());
+            // Undo restores the typed string and cursor position in one step.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("xyz", mTextView.getText().toString());
+            assertEquals(3, mTextView.getSelectionStart());
 
-                // Redo removes the text in one step.
-                mTextView.onTextContextMenuItem(android.R.id.redo);
-                assertEquals("", mTextView.getText().toString());
-                assertEquals(0, mTextView.getSelectionStart());
+            // Redo removes the text in one step.
+            mTextView.onTextContextMenuItem(android.R.id.redo);
+            assertEquals("", mTextView.getText().toString());
+            assertEquals(0, mTextView.getSelectionStart());
 
-                // Undoing the redo restores the text again.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("xyz", mTextView.getText().toString());
-                assertEquals(3, mTextView.getSelectionStart());
+            // Undoing the redo restores the text again.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("xyz", mTextView.getText().toString());
+            assertEquals(3, mTextView.getSelectionStart());
 
-                // Undoing again undoes the original typing.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
-                assertEquals(0, mTextView.getSelectionStart());
-            }
+            // Undoing again undoes the original typing.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
+            assertEquals(0, mTextView.getSelectionStart());
         });
         mInstrumentation.waitForIdleSync();
     }
@@ -1471,9 +1546,13 @@
     // Initialize the text view for simulated IME typing. Must be called on UI thread.
     private InputConnection initTextViewForSimulatedIme() {
         mTextView = findTextView(R.id.textview_text);
-        mTextView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
-        mTextView.setText("", BufferType.EDITABLE);
-        return mTextView.onCreateInputConnection(new EditorInfo());
+        return initTextViewForSimulatedIme(mTextView);
+    }
+
+    private InputConnection initTextViewForSimulatedIme(TextView textView) {
+        textView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
+        textView.setText("", BufferType.EDITABLE);
+        return textView.onCreateInputConnection(new EditorInfo());
     }
 
     // Simulates IME composing text behavior.
@@ -1527,6 +1606,83 @@
     }
 
     @UiThreadTest
+    public void testUndo_imeInsertAndDeleteLatin() {
+        InputConnection input = initTextViewForSimulatedIme();
+
+        setComposingTextInBatch(input, "t");
+        setComposingTextInBatch(input, "te");
+        setComposingTextInBatch(input, "tes");
+        setComposingTextInBatch(input, "test");
+        setComposingTextInBatch(input, "tes");
+        setComposingTextInBatch(input, "te");
+        setComposingTextInBatch(input, "t");
+
+        input.beginBatchEdit();
+        input.setComposingText("", 1);
+        input.finishComposingText();
+        input.endBatchEdit();
+
+        mTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("test", mTextView.getText().toString());
+        mTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("", mTextView.getText().toString());
+    }
+
+    @UiThreadTest
+    public void testUndo_imeAutoCorrection() {
+        mTextView = findTextView(R.id.textview_text);
+        TextView spiedTextView = spy(mTextView);
+        InputConnection input = initTextViewForSimulatedIme(spiedTextView);
+
+        // Start typing a composition.
+        setComposingTextInBatch(input, "t");
+        setComposingTextInBatch(input, "te");
+        setComposingTextInBatch(input, "teh");
+
+        CorrectionInfo correctionInfo = new CorrectionInfo(0, "teh", "the");
+        reset(spiedTextView);
+        input.beginBatchEdit();
+        // Auto correct "teh" to "the".
+        assertTrue(input.commitCorrection(correctionInfo));
+        input.commitText("the", 1);
+        input.endBatchEdit();
+
+        verify(spiedTextView, times(1)).onCommitCorrection(refEq(correctionInfo));
+
+        assertEquals("the", spiedTextView.getText().toString());
+        spiedTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("teh", spiedTextView.getText().toString());
+        spiedTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("", spiedTextView.getText().toString());
+    }
+
+    @UiThreadTest
+    public void testUndo_imeAutoCompletion() {
+        mTextView = findTextView(R.id.textview_text);
+        TextView spiedTextView = spy(mTextView);
+        InputConnection input = initTextViewForSimulatedIme(spiedTextView);
+
+        // Start typing a composition.
+        setComposingTextInBatch(input, "a");
+        setComposingTextInBatch(input, "an");
+        setComposingTextInBatch(input, "and");
+
+        CompletionInfo completionInfo = new CompletionInfo(0, 0, "android");
+        reset(spiedTextView);
+        input.beginBatchEdit();
+        // Auto complete "and" to "android".
+        assertTrue(input.commitCompletion(completionInfo));
+        input.commitText("android", 1);
+        input.endBatchEdit();
+
+        verify(spiedTextView, times(1)).onCommitCompletion(refEq(completionInfo));
+
+        assertEquals("android", spiedTextView.getText().toString());
+        spiedTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("", spiedTextView.getText().toString());
+    }
+
+    @UiThreadTest
     public void testUndo_imeCancel() {
         InputConnection input = initTextViewForSimulatedIme();
         mTextView.setText("flower");
@@ -1540,9 +1696,8 @@
         // Cancel the composition.
         setComposingTextInBatch(input, "");
 
-        // Undo and redo do nothing.
         mTextView.onTextContextMenuItem(android.R.id.undo);
-        assertEquals("flower", mTextView.getText().toString());
+        assertEquals(HA + "n" + "flower", mTextView.getText().toString());
         mTextView.onTextContextMenuItem(android.R.id.redo);
         assertEquals("flower", mTextView.getText().toString());
     }
@@ -1564,409 +1719,364 @@
     }
 
     public void testUndo_setText() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Create two undo operations, an insert and a delete.
-        mKeyEventUtil.sendString(mTextView, "xyz");
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL,
-                KeyEvent.KEYCODE_DEL);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Calling setText() clears both undo operations, so undo doesn't happen.
-                mTextView.setText("Hello", BufferType.EDITABLE);
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("Hello", mTextView.getText().toString());
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "xyz");
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL,
+                KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(() -> {
+            // Calling setText() clears both undo operations, so undo doesn't happen.
+            mTextView.setText("Hello", BufferType.EDITABLE);
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("Hello", mTextView.getText().toString());
 
-                // Clearing text programmatically does not undo either.
-                mTextView.setText("", BufferType.EDITABLE);
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
-            }
+            // Clearing text programmatically does not undo either.
+            mTextView.setText("", BufferType.EDITABLE);
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
         });
         mInstrumentation.waitForIdleSync();
     }
 
     public void testRedo_setText() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Type some text. This creates an undo entry.
-        mKeyEventUtil.sendString(mTextView, "abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Undo the typing to create a redo entry.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivity.runOnUiThread(() -> {
+            // Undo the typing to create a redo entry.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
 
-                // Calling setText() clears the redo stack, so redo doesn't happen.
-                mTextView.setText("Hello", BufferType.EDITABLE);
-                mTextView.onTextContextMenuItem(android.R.id.redo);
-                assertEquals("Hello", mTextView.getText().toString());
-            }
+            // Calling setText() clears the redo stack, so redo doesn't happen.
+            mTextView.setText("Hello", BufferType.EDITABLE);
+            mTextView.onTextContextMenuItem(android.R.id.redo);
+            assertEquals("Hello", mTextView.getText().toString());
         });
         mInstrumentation.waitForIdleSync();
     }
 
     public void testUndo_directAppend() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Type some text.
-        mKeyEventUtil.sendString(mTextView, "abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Programmatically append some text.
-                mTextView.append("def");
-                assertEquals("abcdef", mTextView.getText().toString());
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivity.runOnUiThread(() -> {
+            // Programmatically append some text.
+            mTextView.append("def");
+            assertEquals("abcdef", mTextView.getText().toString());
 
-                // Undo removes the append as a separate step.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("abc", mTextView.getText().toString());
+            // Undo removes the append as a separate step.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("abc", mTextView.getText().toString());
 
-                // Another undo removes the original typing.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
-            }
+            // Another undo removes the original typing.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
         });
         mInstrumentation.waitForIdleSync();
     }
 
     public void testUndo_directInsert() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Type some text.
-        mKeyEventUtil.sendString(mTextView, "abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Directly modify the underlying Editable to insert some text.
-                // NOTE: This is a violation of the API of getText() which specifies that the
-                // returned object should not be modified. However, some apps do this anyway and
-                // the framework needs to handle it.
-                Editable text = (Editable) mTextView.getText();
-                text.insert(0, "def");
-                assertEquals("defabc", mTextView.getText().toString());
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivity.runOnUiThread(() -> {
+            // Directly modify the underlying Editable to insert some text.
+            // NOTE: This is a violation of the API of getText() which specifies that the
+            // returned object should not be modified. However, some apps do this anyway and
+            // the framework needs to handle it.
+            Editable text = (Editable) mTextView.getText();
+            text.insert(0, "def");
+            assertEquals("defabc", mTextView.getText().toString());
 
-                // Undo removes the insert as a separate step.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("abc", mTextView.getText().toString());
+            // Undo removes the insert as a separate step.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("abc", mTextView.getText().toString());
 
-                // Another undo removes the original typing.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
-            }
+            // Another undo removes the original typing.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
         });
         mInstrumentation.waitForIdleSync();
     }
 
+    @UiThreadTest
     public void testUndo_noCursor() {
         initTextViewForTyping();
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Append some text to create an undo operation. There is no cursor present.
-                mTextView.append("cat");
+        // Append some text to create an undo operation. There is no cursor present.
+        mTextView.append("cat");
 
-                // Place the cursor at the end of the text so the undo will have to change it.
-                Selection.setSelection((Spannable) mTextView.getText(), 3);
+        // Place the cursor at the end of the text so the undo will have to change it.
+        Selection.setSelection((Spannable) mTextView.getText(), 3);
 
-                // Undo the append. This should not crash, despite not having a valid cursor
-                // position in the undo operation.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        // Undo the append. This should not crash, despite not having a valid cursor
+        // position in the undo operation.
+        mTextView.onTextContextMenuItem(android.R.id.undo);
     }
 
     public void testUndo_textWatcher() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Add a TextWatcher that converts the text to spaces on each change.
         mTextView.addTextChangedListener(new ConvertToSpacesTextWatcher());
 
         // Type some text.
-        mKeyEventUtil.sendString(mTextView, "abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // TextWatcher altered the text.
-                assertEquals("   ", mTextView.getText().toString());
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivity.runOnUiThread(() -> {
+            // TextWatcher altered the text.
+            assertEquals("   ", mTextView.getText().toString());
 
-                // Undo reverses both changes in one step.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
-            }
+            // Undo reverses both changes in one step.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
         });
         mInstrumentation.waitForIdleSync();
     }
 
+    @UiThreadTest
     public void testUndo_textWatcherDirectAppend() {
         initTextViewForTyping();
 
         // Add a TextWatcher that converts the text to spaces on each change.
         mTextView.addTextChangedListener(new ConvertToSpacesTextWatcher());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Programmatically append some text. The TextWatcher changes it to spaces.
-                mTextView.append("abc");
-                assertEquals("   ", mTextView.getText().toString());
+        // Programmatically append some text. The TextWatcher changes it to spaces.
+        mTextView.append("abc");
+        assertEquals("   ", mTextView.getText().toString());
 
-                // Undo reverses both changes in one step.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        // Undo reverses both changes in one step.
+        mTextView.onTextContextMenuItem(android.R.id.undo);
+        assertEquals("", mTextView.getText().toString());
     }
 
     public void testUndo_shortcuts() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Type some text.
-        mKeyEventUtil.sendString(mTextView, "abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Pressing Control-Z triggers undo.
-                KeyEvent control = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z, 0,
-                        KeyEvent.META_CTRL_LEFT_ON);
-                assertTrue(mTextView.onKeyShortcut(KeyEvent.KEYCODE_Z, control));
-                assertEquals("", mTextView.getText().toString());
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivity.runOnUiThread(() -> {
+            // Pressing Control-Z triggers undo.
+            KeyEvent control = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z, 0,
+                    KeyEvent.META_CTRL_LEFT_ON);
+            assertTrue(mTextView.onKeyShortcut(KeyEvent.KEYCODE_Z, control));
+            assertEquals("", mTextView.getText().toString());
 
-                // Pressing Control-Shift-Z triggers redo.
-                KeyEvent controlShift = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z,
-                        0, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_SHIFT_LEFT_ON);
-                assertTrue(mTextView.onKeyShortcut(KeyEvent.KEYCODE_Z, controlShift));
-                assertEquals("abc", mTextView.getText().toString());
-            }
+            // Pressing Control-Shift-Z triggers redo.
+            KeyEvent controlShift = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z,
+                    0, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_SHIFT_LEFT_ON);
+            assertTrue(mTextView.onKeyShortcut(KeyEvent.KEYCODE_Z, controlShift));
+            assertEquals("abc", mTextView.getText().toString());
         });
         mInstrumentation.waitForIdleSync();
     }
 
     public void testUndo_saveInstanceState() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Type some text to create an undo operation.
-        mKeyEventUtil.sendString(mTextView, "abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Parcel and unparcel the TextView.
-                Parcelable state = mTextView.onSaveInstanceState();
-                mTextView.onRestoreInstanceState(state);
-            }
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivity.runOnUiThread(() -> {
+            // Parcel and unparcel the TextView.
+            Parcelable state = mTextView.onSaveInstanceState();
+            mTextView.onRestoreInstanceState(state);
         });
         mInstrumentation.waitForIdleSync();
 
         // Delete a character to create a new undo operation.
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                assertEquals("ab", mTextView.getText().toString());
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(() -> {
+            assertEquals("ab", mTextView.getText().toString());
 
-                // Undo the delete.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("abc", mTextView.getText().toString());
+            // Undo the delete.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("abc", mTextView.getText().toString());
 
-                // Undo the typing, which verifies that the original undo operation was parceled
-                // correctly.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
+            // Undo the typing, which verifies that the original undo operation was parceled
+            // correctly.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
 
-                // Parcel and unparcel the undo stack (which is empty but has been used and may
-                // contain other state).
-                Parcelable state = mTextView.onSaveInstanceState();
-                mTextView.onRestoreInstanceState(state);
-            }
+            // Parcel and unparcel the undo stack (which is empty but has been used and may
+            // contain other state).
+            Parcelable state = mTextView.onSaveInstanceState();
+            mTextView.onRestoreInstanceState(state);
         });
         mInstrumentation.waitForIdleSync();
     }
 
     public void testUndo_saveInstanceStateEmpty() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Type and delete to create two new undo operations.
-        mKeyEventUtil.sendString(mTextView, "a");
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Empty the undo stack then parcel and unparcel the TextView. While the undo
-                // stack contains no operations it may contain other state.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                Parcelable state = mTextView.onSaveInstanceState();
-                mTextView.onRestoreInstanceState(state);
-            }
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "a");
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(() -> {
+            // Empty the undo stack then parcel and unparcel the TextView. While the undo
+            // stack contains no operations it may contain other state.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            Parcelable state = mTextView.onSaveInstanceState();
+            mTextView.onRestoreInstanceState(state);
         });
         mInstrumentation.waitForIdleSync();
 
         // Create two more undo operations.
-        mKeyEventUtil.sendString(mTextView, "b");
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Verify undo still works.
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("b", mTextView.getText().toString());
-                mTextView.onTextContextMenuItem(android.R.id.undo);
-                assertEquals("", mTextView.getText().toString());
-            }
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "b");
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
+        mActivity.runOnUiThread(() -> {
+            // Verify undo still works.
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("b", mTextView.getText().toString());
+            mTextView.onTextContextMenuItem(android.R.id.undo);
+            assertEquals("", mTextView.getText().toString());
         });
         mInstrumentation.waitForIdleSync();
     }
 
+    @UiThreadTest
     public void testCopyAndPaste() {
         initTextViewForTyping();
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("abcd", BufferType.EDITABLE);
-                mTextView.setSelected(true);
 
-                // Copy "bc".
-                Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
-                mTextView.onTextContextMenuItem(android.R.id.copy);
+        mTextView.setText("abcd", BufferType.EDITABLE);
+        mTextView.setSelected(true);
 
-                // Paste "bc" between "b" and "c".
-                Selection.setSelection((Spannable) mTextView.getText(), 2, 2);
-                mTextView.onTextContextMenuItem(android.R.id.paste);
-                assertEquals("abbccd", mTextView.getText().toString());
+        // Copy "bc".
+        Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
+        mTextView.onTextContextMenuItem(android.R.id.copy);
 
-                // Select entire text and paste "bc".
-                Selection.selectAll((Spannable) mTextView.getText());
-                mTextView.onTextContextMenuItem(android.R.id.paste);
-                assertEquals("bc", mTextView.getText().toString());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        // Paste "bc" between "b" and "c".
+        Selection.setSelection((Spannable) mTextView.getText(), 2, 2);
+        mTextView.onTextContextMenuItem(android.R.id.paste);
+        assertEquals("abbccd", mTextView.getText().toString());
+
+        // Select entire text and paste "bc".
+        Selection.selectAll((Spannable) mTextView.getText());
+        mTextView.onTextContextMenuItem(android.R.id.paste);
+        assertEquals("bc", mTextView.getText().toString());
     }
 
     public void testCopyAndPaste_byKey() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Type "abc".
-        mInstrumentation.sendStringSync("abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Select "bc"
-                Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
-            }
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivity.runOnUiThread(() -> {
+            // Select "bc"
+            Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
         });
         mInstrumentation.waitForIdleSync();
         // Copy "bc"
-        sendKeys(KeyEvent.KEYCODE_COPY);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_COPY);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Set cursor between 'b' and 'c'.
-                Selection.setSelection((Spannable) mTextView.getText(), 2, 2);
-            }
+        mActivity.runOnUiThread(() -> {
+            // Set cursor between 'b' and 'c'.
+            Selection.setSelection((Spannable) mTextView.getText(), 2, 2);
         });
         mInstrumentation.waitForIdleSync();
         // Paste "bc"
-        sendKeys(KeyEvent.KEYCODE_PASTE);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PASTE);
         assertEquals("abbcc", mTextView.getText().toString());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                Selection.selectAll((Spannable) mTextView.getText());
-                KeyEvent copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
-                        KeyEvent.KEYCODE_COPY, 0, KeyEvent.META_SHIFT_LEFT_ON);
-                // Shift + copy doesn't perform copy.
-                mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
-                Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
-                mTextView.onTextContextMenuItem(android.R.id.paste);
-                assertEquals("bcabbcc", mTextView.getText().toString());
+        mActivity.runOnUiThread(() -> {
+            Selection.selectAll((Spannable) mTextView.getText());
+            KeyEvent copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+                    KeyEvent.KEYCODE_COPY, 0, KeyEvent.META_SHIFT_LEFT_ON);
+            // Shift + copy doesn't perform copy.
+            mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
+            Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+            mTextView.onTextContextMenuItem(android.R.id.paste);
+            assertEquals("bcabbcc", mTextView.getText().toString());
 
-                Selection.selectAll((Spannable) mTextView.getText());
-                copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_COPY, 0,
-                        KeyEvent.META_CTRL_LEFT_ON);
-                // Control + copy doesn't perform copy.
-                mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
-                Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
-                mTextView.onTextContextMenuItem(android.R.id.paste);
-                assertEquals("bcbcabbcc", mTextView.getText().toString());
+            Selection.selectAll((Spannable) mTextView.getText());
+            copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_COPY, 0,
+                    KeyEvent.META_CTRL_LEFT_ON);
+            // Control + copy doesn't perform copy.
+            mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
+            Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+            mTextView.onTextContextMenuItem(android.R.id.paste);
+            assertEquals("bcbcabbcc", mTextView.getText().toString());
 
-                Selection.selectAll((Spannable) mTextView.getText());
-                copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_COPY, 0,
-                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_CTRL_LEFT_ON);
-                // Control + Shift + copy doesn't perform copy.
-                mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
-                Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
-                mTextView.onTextContextMenuItem(android.R.id.paste);
-                assertEquals("bcbcbcabbcc", mTextView.getText().toString());
-            }
+            Selection.selectAll((Spannable) mTextView.getText());
+            copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_COPY, 0,
+                    KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_CTRL_LEFT_ON);
+            // Control + Shift + copy doesn't perform copy.
+            mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
+            Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+            mTextView.onTextContextMenuItem(android.R.id.paste);
+            assertEquals("bcbcbcabbcc", mTextView.getText().toString());
         });
         mInstrumentation.waitForIdleSync();
     }
 
+    @UiThreadTest
     public void testCutAndPaste() {
         initTextViewForTyping();
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("abcd", BufferType.EDITABLE);
-                mTextView.setSelected(true);
 
-                // Cut "bc".
-                Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
-                mTextView.onTextContextMenuItem(android.R.id.cut);
-                assertEquals("ad", mTextView.getText().toString());
+        mTextView.setText("abcd", BufferType.EDITABLE);
+        mTextView.setSelected(true);
 
-                // Cut "ad".
-                Selection.setSelection((Spannable) mTextView.getText(), 0, 2);
-                mTextView.onTextContextMenuItem(android.R.id.cut);
-                assertEquals("", mTextView.getText().toString());
+        // Cut "bc".
+        Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
+        mTextView.onTextContextMenuItem(android.R.id.cut);
+        assertEquals("ad", mTextView.getText().toString());
 
-                // Paste "ad".
-                mTextView.onTextContextMenuItem(android.R.id.paste);
-                assertEquals("ad", mTextView.getText().toString());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        // Cut "ad".
+        Selection.setSelection((Spannable) mTextView.getText(), 0, 2);
+        mTextView.onTextContextMenuItem(android.R.id.cut);
+        assertEquals("", mTextView.getText().toString());
+
+        // Paste "ad".
+        mTextView.onTextContextMenuItem(android.R.id.paste);
+        assertEquals("ad", mTextView.getText().toString());
     }
 
     public void testCutAndPaste_byKey() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
         // Type "abc".
-        mInstrumentation.sendStringSync("abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Select "bc"
-                Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
-            }
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivity.runOnUiThread(() -> {
+            // Select "bc"
+            Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
         });
         mInstrumentation.waitForIdleSync();
         // Cut "bc"
-        sendKeys(KeyEvent.KEYCODE_CUT);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_CUT);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                assertEquals("a", mTextView.getText().toString());
-                // Move cursor to the head
-                Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
-            }
+        mActivity.runOnUiThread(() -> {
+            assertEquals("a", mTextView.getText().toString());
+            // Move cursor to the head
+            Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
         });
         mInstrumentation.waitForIdleSync();
         // Paste "bc"
-        sendKeys(KeyEvent.KEYCODE_PASTE);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_PASTE);
         assertEquals("bca", mTextView.getText().toString());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                Selection.selectAll((Spannable) mTextView.getText());
-                KeyEvent cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
-                        KeyEvent.KEYCODE_CUT, 0, KeyEvent.META_SHIFT_LEFT_ON);
-                // Shift + cut doesn't perform cut.
-                mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
-                assertEquals("bca", mTextView.getText().toString());
+        mInstrumentation.runOnMainSync(() -> {
+            Selection.selectAll((Spannable) mTextView.getText());
+            KeyEvent cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+                    KeyEvent.KEYCODE_CUT, 0, KeyEvent.META_SHIFT_LEFT_ON);
+            // Shift + cut doesn't perform cut.
+            mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
+            assertEquals("bca", mTextView.getText().toString());
 
-                cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_CUT, 0,
-                        KeyEvent.META_CTRL_LEFT_ON);
-                // Control + cut doesn't perform cut.
-                mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
-                assertEquals("bca", mTextView.getText().toString());
+            cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_CUT, 0,
+                    KeyEvent.META_CTRL_LEFT_ON);
+            // Control + cut doesn't perform cut.
+            mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
+            assertEquals("bca", mTextView.getText().toString());
 
-                cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_CUT, 0,
-                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_CTRL_LEFT_ON);
-                // Control + Shift + cut doesn't perform cut.
-                mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
-                assertEquals("bca", mTextView.getText().toString());
-            }
+            cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_CUT, 0,
+                    KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_CTRL_LEFT_ON);
+            // Control + Shift + cut doesn't perform cut.
+            mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
+            assertEquals("bca", mTextView.getText().toString());
         });
+        mInstrumentation.waitForIdleSync();
     }
 
     private static boolean hasSpansAtMiddleOfText(final TextView textView, final Class<?> type) {
@@ -1975,38 +2085,35 @@
         return spannable.getSpans(at, at, type).length > 0;
     }
 
+    @UiThreadTest
     public void testCutAndPaste_withAndWithoutStyle() {
         initTextViewForTyping();
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("example", BufferType.EDITABLE);
-                mTextView.setSelected(true);
 
-                // Set URLSpan.
-                final Spannable spannable = (Spannable) mTextView.getText();
-                spannable.setSpan(new URLSpan("http://example.com"), 0, spannable.length(), 0);
-                assertTrue(hasSpansAtMiddleOfText(mTextView, URLSpan.class));
+        mTextView.setText("example", BufferType.EDITABLE);
+        mTextView.setSelected(true);
 
-                // Cut entire text.
-                Selection.selectAll((Spannable) mTextView.getText());
-                mTextView.onTextContextMenuItem(android.R.id.cut);
-                assertEquals("", mTextView.getText().toString());
+        // Set URLSpan.
+        final Spannable spannable = (Spannable) mTextView.getText();
+        spannable.setSpan(new URLSpan("http://example.com"), 0, spannable.length(), 0);
+        assertTrue(hasSpansAtMiddleOfText(mTextView, URLSpan.class));
 
-                // Paste without style.
-                mTextView.onTextContextMenuItem(android.R.id.pasteAsPlainText);
-                assertEquals("example", mTextView.getText().toString());
-                // Check that the text doesn't have URLSpan.
-                assertFalse(hasSpansAtMiddleOfText(mTextView, URLSpan.class));
+        // Cut entire text.
+        Selection.selectAll((Spannable) mTextView.getText());
+        mTextView.onTextContextMenuItem(android.R.id.cut);
+        assertEquals("", mTextView.getText().toString());
 
-                // Paste with style.
-                Selection.selectAll((Spannable) mTextView.getText());
-                mTextView.onTextContextMenuItem(android.R.id.paste);
-                assertEquals("example", mTextView.getText().toString());
-                // Check that the text has URLSpan.
-                assertTrue(hasSpansAtMiddleOfText(mTextView, URLSpan.class));
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        // Paste without style.
+        mTextView.onTextContextMenuItem(android.R.id.pasteAsPlainText);
+        assertEquals("example", mTextView.getText().toString());
+        // Check that the text doesn't have URLSpan.
+        assertFalse(hasSpansAtMiddleOfText(mTextView, URLSpan.class));
+
+        // Paste with style.
+        Selection.selectAll((Spannable) mTextView.getText());
+        mTextView.onTextContextMenuItem(android.R.id.paste);
+        assertEquals("example", mTextView.getText().toString());
+        // Check that the text has URLSpan.
+        assertTrue(hasSpansAtMiddleOfText(mTextView, URLSpan.class));
     }
 
     @UiThreadTest
@@ -2185,61 +2292,45 @@
 
         final String errorText = "Oops! There is an error";
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setError(null);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setError(null));
         mInstrumentation.waitForIdleSync();
         assertNull(mTextView.getError());
 
-        final Drawable icon = getDrawable(R.drawable.failed);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setError(errorText, icon);
-            }
-        });
+        final Drawable icon = TestUtils.getDrawable(mActivity, R.drawable.failed);
+        mActivity.runOnUiThread(() -> mTextView.setError(errorText, icon));
         mInstrumentation.waitForIdleSync();
         assertEquals(errorText, mTextView.getError().toString());
         // can not check whether the drawable is set correctly
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setError(null, null);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setError(null, null));
         mInstrumentation.waitForIdleSync();
         assertNull(mTextView.getError());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(DigitsKeyListener.getInstance(""));
-                mTextView.setText("", BufferType.EDITABLE);
-                mTextView.setError(errorText);
-                mTextView.requestFocus();
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setKeyListener(DigitsKeyListener.getInstance(""));
+            mTextView.setText("", BufferType.EDITABLE);
+            mTextView.setError(errorText);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
         assertEquals(errorText, mTextView.getError().toString());
 
-        mInstrumentation.sendStringSync("a");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "a");
         // a key event that will not change the TextView's text
         assertEquals("", mTextView.getText().toString());
         // The icon and error message will not be reset to null
         assertEquals(errorText, mTextView.getError().toString());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(DigitsKeyListener.getInstance());
-                mTextView.setText("", BufferType.EDITABLE);
-                mTextView.setError(errorText);
-                mTextView.requestFocus();
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setKeyListener(DigitsKeyListener.getInstance());
+            mTextView.setText("", BufferType.EDITABLE);
+            mTextView.setError(errorText);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
-        mInstrumentation.sendStringSync("1");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "1");
         // a key event cause changes to the TextView's text
         assertEquals("1", mTextView.getText().toString());
         // the error message and icon will be cleared.
@@ -2252,26 +2343,24 @@
 
         final QwertyKeyListener qwertyKeyListener
                 = QwertyKeyListener.getInstance(false, Capitalize.NONE);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = findTextView(R.id.textview_text);
-                mTextView.setKeyListener(qwertyKeyListener);
-                mTextView.setText("", BufferType.EDITABLE);
-                mTextView.setFilters(expected);
-                mTextView.requestFocus();
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView = findTextView(R.id.textview_text);
+            mTextView.setKeyListener(qwertyKeyListener);
+            mTextView.setText("", BufferType.EDITABLE);
+            mTextView.setFilters(expected);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
         assertSame(expected, mTextView.getFilters());
 
-        mInstrumentation.sendStringSync("a");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "a");
         // the text is capitalized by InputFilter.AllCaps
         assertEquals("A", mTextView.getText().toString());
-        mInstrumentation.sendStringSync("b");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "b");
         // the text is capitalized by InputFilter.AllCaps
         assertEquals("AB", mTextView.getText().toString());
-        mInstrumentation.sendStringSync("c");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "c");
         // 'C' could not be accepted, because there is a length filter.
         assertEquals("AB", mTextView.getText().toString());
 
@@ -2301,13 +2390,11 @@
         assertEquals(mTextView.getScrollY(), rc.top);
         assertEquals(mTextView.getScrollY() + mTextView.getHeight(), rc.bottom);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setSelected(true);
-                SpannableString text = new SpannableString(mTextView.getText());
-                Selection.setSelection(text, 3, 13);
-                mTextView.setText(text);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setSelected(true);
+            SpannableString text = new SpannableString(mTextView.getText());
+            Selection.setSelection(text, 3, 13);
+            mTextView.setText(text);
         });
         mInstrumentation.waitForIdleSync();
         mTextView.getFocusedRect(rc);
@@ -2322,13 +2409,11 @@
         assertEquals(mTextView.getLayout().getLineTop(0), rc.top);
         assertEquals(mTextView.getLayout().getLineBottom(0), rc.bottom);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setSelected(true);
-                SpannableString text = new SpannableString(mTextView.getText());
-                Selection.setSelection(text, 13, 3);
-                mTextView.setText(text);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setSelected(true);
+            SpannableString text = new SpannableString(mTextView.getText());
+            Selection.setSelection(text, 13, 3);
+            mTextView.setText(text);
         });
         mInstrumentation.waitForIdleSync();
         mTextView.getFocusedRect(rc);
@@ -2346,13 +2431,11 @@
         assertEquals(mTextView.getScrollY(), rc.top);
         assertEquals(mTextView.getScrollY() + mTextView.getHeight(), rc.bottom);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setSelected(true);
-                SpannableString text = new SpannableString(mTextView.getText());
-                Selection.setSelection(text, 2, 4);
-                mTextView.setText(text);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setSelected(true);
+            SpannableString text = new SpannableString(mTextView.getText());
+            Selection.setSelection(text, 2, 4);
+            mTextView.setText(text);
         });
         mInstrumentation.waitForIdleSync();
         mTextView.getFocusedRect(rc);
@@ -2362,13 +2445,11 @@
         assertEquals(mTextView.getLayout().getLineTop(0), rc.top);
         assertEquals(mTextView.getLayout().getLineBottom(0), rc.bottom);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setSelected(true);
-                SpannableString text = new SpannableString(mTextView.getText());
-                Selection.setSelection(text, 2, 10); // cross the "\n" and two lines
-                mTextView.setText(text);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setSelected(true);
+            SpannableString text = new SpannableString(mTextView.getText());
+            Selection.setSelection(text, 2, 10); // cross the "\n" and two lines
+            mTextView.setText(text);
         });
         mInstrumentation.waitForIdleSync();
         mTextView.getFocusedRect(rc);
@@ -2433,11 +2514,9 @@
         assertEquals(0, rc.top);
         assertEquals(mTextView.getHeight(), rc.bottom);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setPadding(1, 2, 3, 4);
-                mTextView.setGravity(Gravity.BOTTOM);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setPadding(1, 2, 3, 4);
+            mTextView.setGravity(Gravity.BOTTOM);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(mTextView.getBaseline(), mTextView.getLineBounds(0, rc));
@@ -2454,11 +2533,9 @@
         mTextView = findTextView(R.id.textview_text);
         assertEquals(mTextView.getLayout().getLineBaseline(0), mTextView.getBaseline());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setPadding(1, 2, 3, 4);
-                mTextView.setGravity(Gravity.BOTTOM);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setPadding(1, 2, 3, 4);
+            mTextView.setGravity(Gravity.BOTTOM);
         });
         mInstrumentation.waitForIdleSync();
         int expected = mTextView.getTotalPaddingTop() + mTextView.getLayout().getLineBaseline(0);
@@ -2466,34 +2543,28 @@
     }
 
     public void testPressKey() {
-        initTextViewForTyping();
+        initTextViewForTypingOnUiThread();
 
-        mInstrumentation.sendStringSync("a");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "a");
         assertEquals("a", mTextView.getText().toString());
-        mInstrumentation.sendStringSync("b");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "b");
         assertEquals("ab", mTextView.getText().toString());
-        sendKeys(KeyEvent.KEYCODE_DEL);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
         assertEquals("a", mTextView.getText().toString());
     }
 
     public void testSetIncludeFontPadding() {
         mTextView = findTextView(R.id.textview_text);
         assertTrue(mTextView.getIncludeFontPadding());
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setWidth(mTextView.getWidth() / 3);
-                mTextView.setPadding(1, 2, 3, 4);
-                mTextView.setGravity(Gravity.BOTTOM);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setWidth(mTextView.getWidth() / 3);
+            mTextView.setPadding(1, 2, 3, 4);
+            mTextView.setGravity(Gravity.BOTTOM);
         });
         mInstrumentation.waitForIdleSync();
 
         int oldHeight = mTextView.getHeight();
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setIncludeFontPadding(false);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setIncludeFontPadding(false));
         mInstrumentation.waitForIdleSync();
 
         assertTrue(mTextView.getHeight() < oldHeight);
@@ -2557,6 +2628,31 @@
         assertTrue(mTextView.hasSelection());
     }
 
+    @MediumTest
+    public void testOnSelectionChanged_isTriggeredWhenSelectionChanges() {
+        final MockTextView textView = spy(new MockTextView(mActivity));
+        final String text = "any text";
+        textView.setText(text, BufferType.SPANNABLE);
+
+        // assert that there is currently no selection
+        assertFalse(textView.hasSelection());
+
+        // select all
+        Selection.selectAll((Spannable) textView.getText());
+        // After selectAll OnSelectionChanged should have been called
+        verify(textView, times(1)).onSelectionChanged(0, text.length());
+
+        reset(textView);
+        // change selection
+        Selection.setSelection((Spannable) textView.getText(), 1, 5);
+        verify(textView, times(1)).onSelectionChanged(1, 5);
+
+        reset(textView);
+        // clear selection
+        Selection.removeSelection((Spannable) textView.getText());
+        verify(textView, times(1)).onSelectionChanged(-1, -1);
+    }
+
     @UiThreadTest
     public void testAccessEllipsize() {
         mActivity.setContentView(R.layout.textview_ellipsize);
@@ -2598,18 +2694,18 @@
     }
 
     public void testEllipsizeEndAndNoEllipsizeHasSameBaselineForSingleLine() {
-        int textWidth = calculateTextWidth(LONG_TEXT);
-
         TextView tvEllipsizeEnd = new TextView(getActivity());
         tvEllipsizeEnd.setEllipsize(TruncateAt.END);
         tvEllipsizeEnd.setMaxLines(1);
-        tvEllipsizeEnd.setWidth(textWidth >> 2);
         tvEllipsizeEnd.setText(LONG_TEXT);
 
         TextView tvEllipsizeNone = new TextView(getActivity());
-        tvEllipsizeNone.setWidth(textWidth >> 2);
         tvEllipsizeNone.setText("a");
 
+        final int textWidth = (int) tvEllipsizeEnd.getPaint().measureText(LONG_TEXT) / 4;
+        tvEllipsizeEnd.setWidth(textWidth);
+        tvEllipsizeNone.setWidth(textWidth);
+
         final FrameLayout layout = new FrameLayout(mActivity);
         ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
@@ -2618,12 +2714,7 @@
         layout.addView(tvEllipsizeNone, layoutParams);
         layout.setLayoutParams(layoutParams);
 
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setContentView(layout);
-            }
-        });
+        mActivity.runOnUiThread(() -> getActivity().setContentView(layout));
         getInstrumentation().waitForIdleSync();
 
         assertEquals("Ellipsized and non ellipsized single line texts should have the same " +
@@ -2633,19 +2724,19 @@
     }
 
     public void testEllipsizeEndAndNoEllipsizeHasSameBaselineForMultiLine() {
-        int textWidth = calculateTextWidth(LONG_TEXT);
-
         TextView tvEllipsizeEnd = new TextView(getActivity());
         tvEllipsizeEnd.setEllipsize(TruncateAt.END);
         tvEllipsizeEnd.setMaxLines(2);
-        tvEllipsizeEnd.setWidth(textWidth >> 2);
         tvEllipsizeEnd.setText(LONG_TEXT);
 
         TextView tvEllipsizeNone = new TextView(getActivity());
         tvEllipsizeNone.setMaxLines(2);
-        tvEllipsizeNone.setWidth(textWidth >> 2);
         tvEllipsizeNone.setText(LONG_TEXT);
 
+        final int textWidth = (int) tvEllipsizeEnd.getPaint().measureText(LONG_TEXT) / 2;
+        tvEllipsizeEnd.setWidth(textWidth);
+        tvEllipsizeNone.setWidth(textWidth);
+
         final FrameLayout layout = new FrameLayout(mActivity);
         ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
@@ -2655,12 +2746,7 @@
         layout.addView(tvEllipsizeNone, layoutParams);
         layout.setLayoutParams(layoutParams);
 
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setContentView(layout);
-            }
-        });
+        mActivity.runOnUiThread(() -> getActivity().setContentView(layout));
         getInstrumentation().waitForIdleSync();
 
         for (int i = 0; i < tvEllipsizeEnd.getLineCount(); i++) {
@@ -2671,11 +2757,51 @@
         }
     }
 
-    public void testSetCursorVisible() {
+    public void testTextViewInWeigthenedLayoutChangesWidthAfterSetText() {
+        final TextView textView = new TextView(getActivity());
+        textView.setEllipsize(TruncateAt.END);
+        textView.setSingleLine(true);
+        textView.setText("a");
+
+        TextView otherTextView = new TextView(getActivity());
+        otherTextView.setSingleLine(true);
+        otherTextView.setText("any");
+
+        final LinearLayout layout = new LinearLayout(mActivity);
+        layout.setOrientation(LinearLayout.HORIZONTAL);
+
+        // TextView under test has weight 1, and width 0
+        layout.addView(textView, new LinearLayout.LayoutParams(0,
+                ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
+
+        // other TextView has default weight
+        layout.addView(otherTextView, new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+
+        // main layout params
+        layout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+        mActivity.runOnUiThread(() -> getActivity().setContentView(layout));
+        getInstrumentation().waitForIdleSync();
+
+        int oldWidth = textView.getWidth();
+
+        mActivity.runOnUiThread(() -> textView.setText("aaa"));
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("TextView should have larger width after a longer text is set",
+                textView.getWidth() > oldWidth);
+    }
+
+    public void testAccessCursorVisible() {
         mTextView = new TextView(mActivity);
 
         mTextView.setCursorVisible(true);
+        assertTrue(mTextView.isCursorVisible());
         mTextView.setCursorVisible(false);
+        assertFalse(mTextView.isCursorVisible());
     }
 
     public void testOnWindowFocusChanged() {
@@ -2702,27 +2828,39 @@
     public void testPerformLongClick() {
         mTextView = findTextView(R.id.textview_text);
         mTextView.setText("This is content");
-        MockOnLongClickListener onLongClickListener = new MockOnLongClickListener(true);
-        MockOnCreateContextMenuListener onCreateContextMenuListener
-                = new MockOnCreateContextMenuListener(false);
-        mTextView.setOnLongClickListener(onLongClickListener);
-        mTextView.setOnCreateContextMenuListener(onCreateContextMenuListener);
-        assertTrue(mTextView.performLongClick());
-        assertTrue(onLongClickListener.hasLongClicked());
-        assertFalse(onCreateContextMenuListener.hasCreatedContextMenu());
 
-        onLongClickListener = new MockOnLongClickListener(false);
-        mTextView.setOnLongClickListener(onLongClickListener);
-        mTextView.setOnCreateContextMenuListener(onCreateContextMenuListener);
-        assertTrue(mTextView.performLongClick());
-        assertTrue(onLongClickListener.hasLongClicked());
-        assertTrue(onCreateContextMenuListener.hasCreatedContextMenu());
+        View.OnLongClickListener mockOnLongClickListener = mock(View.OnLongClickListener.class);
+        when(mockOnLongClickListener.onLongClick(any(View.class))).thenReturn(Boolean.TRUE);
 
+        View.OnCreateContextMenuListener mockOnCreateContextMenuListener =
+                mock(View.OnCreateContextMenuListener.class);
+        doAnswer((InvocationOnMock invocation) -> {
+            ((ContextMenu) invocation.getArguments() [0]).add("menu item");
+            return null;
+        }).when(mockOnCreateContextMenuListener).onCreateContextMenu(
+                any(ContextMenu.class), any(View.class), any(ContextMenuInfo.class));
+
+        mTextView.setOnLongClickListener(mockOnLongClickListener);
+        mTextView.setOnCreateContextMenuListener(mockOnCreateContextMenuListener);
+        assertTrue(mTextView.performLongClick());
+        verify(mockOnLongClickListener, times(1)).onLongClick(mTextView);
+        verifyZeroInteractions(mockOnCreateContextMenuListener);
+
+        reset(mockOnLongClickListener);
+        when(mockOnLongClickListener.onLongClick(any(View.class))).thenReturn(Boolean.FALSE);
+        assertTrue(mTextView.performLongClick());
+        verify(mockOnLongClickListener, times(1)).onLongClick(mTextView);
+        verify(mockOnCreateContextMenuListener, times(1)).onCreateContextMenu(
+                any(ContextMenu.class), eq(mTextView), any(ContextMenuInfo.class));
+
+        reset(mockOnCreateContextMenuListener);
         mTextView.setOnLongClickListener(null);
-        onCreateContextMenuListener = new MockOnCreateContextMenuListener(true);
-        mTextView.setOnCreateContextMenuListener(onCreateContextMenuListener);
+        doNothing().when(mockOnCreateContextMenuListener).onCreateContextMenu(
+                any(ContextMenu.class), any(View.class), any(ContextMenuInfo.class));
         assertFalse(mTextView.performLongClick());
-        assertTrue(onCreateContextMenuListener.hasCreatedContextMenu());
+        verifyNoMoreInteractions(mockOnLongClickListener);
+        verify(mockOnCreateContextMenuListener, times(1)).onCreateContextMenu(
+                any(ContextMenu.class), eq(mTextView), any(ContextMenuInfo.class));
     }
 
     @UiThreadTest
@@ -2952,6 +3090,259 @@
                 urlSpans[0].getURL(), "http://android.com/textview");
     }
 
+    @MediumTest
+    public void testGetLetterSpacing_returnsValueThatWasSet() {
+        mTextView = new TextView(mActivity);
+        mTextView.setLetterSpacing(2f);
+        assertEquals("getLetterSpacing should return the value that was set",
+                2f, mTextView.getLetterSpacing());
+    }
+
+    @MediumTest
+    public void testSetLetterSpacing_changesTextWidth() {
+        final TextView textView = new TextView(mActivity);
+        textView.setText("aa");
+        textView.setLetterSpacing(0f);
+        textView.setTextSize(8f);
+
+        final FrameLayout layout = new FrameLayout(mActivity);
+        final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        layout.addView(textView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mActivity.runOnUiThread(() -> getActivity().setContentView(layout));
+        getInstrumentation().waitForIdleSync();
+
+        // measure text with zero letter spacing
+        final float zeroSpacing = textView.getLayout().getLineWidth(0);
+
+        getActivity().runOnUiThread(() -> textView.setLetterSpacing(1f));
+        getInstrumentation().waitForIdleSync();
+
+        // measure text with single letter spacing
+        final float singleSpacing = textView.getLayout().getLineWidth(0);
+
+        getActivity().runOnUiThread(() -> textView.setLetterSpacing(2f));
+        getInstrumentation().waitForIdleSync();
+
+        // measure text with double letter spacing
+        final float doubleSpacing = textView.getLayout().getLineWidth(0);
+
+        assertEquals("Double spacing should have two times the spacing of single spacing",
+                doubleSpacing - zeroSpacing, 2f * (singleSpacing - zeroSpacing), 1f);
+    }
+
+    @MediumTest
+    public void testGetFontFeatureSettings_returnsValueThatWasSet() {
+        mTextView = new TextView(mActivity);
+        mTextView.setFontFeatureSettings("\"smcp\" on");
+        assertEquals("getFontFeatureSettings should return the value that was set",
+                "\"smcp\" on", mTextView.getFontFeatureSettings());
+    }
+
+    @MediumTest
+    public void testGetOffsetForPosition_singleLineLtr() {
+        // asserts getOffsetPosition returns correct values for a single line LTR text
+        String text = "aaaaa";
+        final TextView textView = new TextView(mActivity);
+        textView.setText(text);
+        textView.setTextSize(8f);
+        textView.setSingleLine(true);
+
+        // add a compound drawable to TextView to make offset calculation more interesting
+        final Drawable drawable = TestUtils.getDrawable(mActivity, R.drawable.red);
+        drawable.setBounds(0, 0, 10, 10);
+        textView.setCompoundDrawables(drawable, drawable, drawable, drawable);
+
+        final FrameLayout layout = new FrameLayout(mActivity);
+        final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        layout.addView(textView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mInstrumentation.runOnMainSync(() -> getActivity().setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        final int firstOffset = 0;
+        final int lastOffset = text.length() - 1;
+        final int midOffset = text.length() / 2;
+
+        // left edge of view
+        float x = 0f;
+        float y = textView.getHeight() / 2f;
+        assertEquals(firstOffset, textView.getOffsetForPosition(x, y));
+
+        // right edge of text
+        x = textView.getLayout().getLineWidth(0) - 1f;
+        assertEquals(lastOffset, textView.getOffsetForPosition(x, y));
+
+        // right edge of view
+        x = textView.getWidth();
+        assertEquals(lastOffset + 1, textView.getOffsetForPosition(x, y));
+
+        // left edge of view - out of bounds
+        x = -1f;
+        assertEquals(firstOffset, textView.getOffsetForPosition(x, y));
+
+        // horizontal center of text
+        x = (float) Math.floor(textView.getLayout().getLineWidth(0) / 2f + 0.5f);
+        assertEquals(midOffset, textView.getOffsetForPosition(x, y));
+    }
+
+    @MediumTest
+    public void testGetOffsetForPosition_multiLineLtr() {
+        final String line = "aaa\n";
+        final String threeLines = line + line + line;
+        final TextView textView = new TextView(mActivity);
+        textView.setText(threeLines);
+        textView.setTextSize(8f);
+        textView.setLines(2);
+
+        // add a compound drawable to TextView to make offset calculation more interesting
+        final Drawable drawable = TestUtils.getDrawable(mActivity, R.drawable.red);
+        drawable.setBounds(0, 0, 10, 10);
+        textView.setCompoundDrawables(drawable, drawable, drawable, drawable);
+
+        final FrameLayout layout = new FrameLayout(mActivity);
+        final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        layout.addView(textView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mInstrumentation.runOnMainSync(() -> getActivity().setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        final Rect lineBounds = new Rect();
+        textView.getLayout().getLineBounds(0, lineBounds);
+
+        // left edge of view at first line
+        float x = 0f;
+        float y = lineBounds.height() / 2f;
+        assertEquals(0, textView.getOffsetForPosition(x, y));
+
+        // right edge of view at first line
+        x = textView.getWidth() - 1f;
+        assertEquals(line.length() - 1, textView.getOffsetForPosition(x, y));
+
+        // update lineBounds to be the second line
+        textView.getLayout().getLineBounds(1, lineBounds);
+        y = lineBounds.top + lineBounds.height() / 2;
+
+        // left edge of view at second line
+        x = 0f;
+        assertEquals(line.length(), textView.getOffsetForPosition(x, y));
+
+        // right edge of text at second line
+        x = textView.getLayout().getLineWidth(1) - 1f;
+        assertEquals(line.length() + line.length() - 1, textView.getOffsetForPosition(x, y));
+
+        // right edge of view at second line
+        x = textView.getWidth() - 1f;
+        assertEquals(line.length() + line.length() - 1, textView.getOffsetForPosition(x, y));
+
+        // horizontal center of text at second line
+        x = (float) Math.floor(textView.getLayout().getLineWidth(1) / 2f + 0.5f);
+        // second line mid offset should not include next line, therefore subtract one
+        assertEquals(line.length() + (line.length() - 1) / 2, textView.getOffsetForPosition(x, y));
+    }
+
+    @MediumTest
+    public void testGetOffsetForPosition_multiLineRtl() {
+        final String line = "\u0635\u0635\u0635\n";
+        final String threeLines = line + line + line;
+        final TextView textView = new TextView(mActivity);
+        textView.setText(threeLines);
+        textView.setTextSize(8f);
+        textView.setLines(2);
+
+        // add a compound drawable to TextView to make offset calculation more interesting
+        final Drawable drawable = TestUtils.getDrawable(mActivity, R.drawable.red);
+        drawable.setBounds(0, 0, 10, 10);
+        textView.setCompoundDrawables(drawable, drawable, drawable, drawable);
+
+        final FrameLayout layout = new FrameLayout(mActivity);
+        final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        layout.addView(textView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mInstrumentation.runOnMainSync(() -> getActivity().setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        final Rect lineBounds = new Rect();
+        textView.getLayout().getLineBounds(0, lineBounds);
+
+        // right edge of view at first line
+        float x = textView.getWidth() - 1f;
+        float y = lineBounds.height() / 2f;
+        assertEquals(0, textView.getOffsetForPosition(x, y));
+
+        // left edge of view at first line
+        x = 0f;
+        assertEquals(line.length() - 1, textView.getOffsetForPosition(x, y));
+
+        // update lineBounds to be the second line
+        textView.getLayout().getLineBounds(1, lineBounds);
+        y = lineBounds.top + lineBounds.height() / 2f;
+
+        // right edge of view at second line
+        x = textView.getWidth() - 1f;
+        assertEquals(line.length(), textView.getOffsetForPosition(x, y));
+
+        // left edge of view at second line
+        x = 0f;
+        assertEquals(line.length() + line.length() - 1, textView.getOffsetForPosition(x, y));
+
+        // right edge of text at second line
+        x = textView.getWidth() - textView.getLayout().getLineWidth(1) + 1f;
+        assertEquals(line.length() + line.length() - 1, textView.getOffsetForPosition(x, y));
+
+        // horizontal center of text at second line
+        x = textView.getWidth() - (float) Math.floor(
+                textView.getLayout().getLineWidth(1) / 2f + 0.5f);
+        // second line mid offset should not include next line, therefore subtract one
+        assertEquals(line.length() + (line.length() - 1) / 2, textView.getOffsetForPosition(x, y));
+    }
+
+    @MediumTest
+    public void testIsTextSelectable_returnsFalseByDefault() {
+        final TextView textView = new TextView(getActivity());
+        textView.setText("any text");
+        assertFalse(textView.isTextSelectable());
+    }
+
+    @MediumTest
+    public void testIsTextSelectable_returnsTrueIfSetTextIsSelectableCalledWithTrue() {
+        final TextView textView = new TextView(getActivity());
+        textView.setText("any text");
+        textView.setTextIsSelectable(true);
+        assertTrue(textView.isTextSelectable());
+    }
+
+    @MediumTest
+    public void testSetIsTextSelectable() {
+        final TextView textView = new TextView(getActivity());
+
+        assertFalse(textView.isTextSelectable());
+        assertFalse(textView.isFocusable());
+        assertFalse(textView.isFocusableInTouchMode());
+        assertFalse(textView.isClickable());
+        assertFalse(textView.isLongClickable());
+
+        textView.setTextIsSelectable(true);
+
+        assertTrue(textView.isTextSelectable());
+        assertTrue(textView.isFocusable());
+        assertTrue(textView.isFocusableInTouchMode());
+        assertTrue(textView.isClickable());
+        assertTrue(textView.isLongClickable());
+        assertNotNull(textView.getMovementMethod());
+    }
 
     public void testAccessTransformationMethod() {
         // check the password attribute in xml
@@ -2970,43 +3361,28 @@
                 Capitalize.NONE);
         final TransformationMethod method = PasswordTransformationMethod.getInstance();
         // change transformation method by function
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(qwertyKeyListener);
-                mTextView.setTransformationMethod(method);
-                mTransformedText = method.getTransformation(mTextView.getText(), mTextView);
+        mActivity.runOnUiThread(() -> {
+            mTextView.setKeyListener(qwertyKeyListener);
+            mTextView.setTransformationMethod(method);
+            mTransformedText = method.getTransformation(mTextView.getText(), mTextView);
 
-                mTextView.requestFocus();
-            }
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
         assertSame(PasswordTransformationMethod.getInstance(),
                 mTextView.getTransformationMethod());
 
-        sendKeys("H E 2*L O");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.append(" ");
-            }
-        });
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, "H E 2*L O");
+        mActivity.runOnUiThread(() -> mTextView.append(" "));
         mInstrumentation.waitForIdleSync();
 
-        // it will get transformed after a while
-        new PollingCheck(TIMEOUT) {
-            @Override
-            protected boolean check() {
-                // "******"
-                return mTransformedText.toString()
-                        .equals("\u2022\u2022\u2022\u2022\u2022\u2022");
-            }
-        }.run();
+        // It will get transformed after a while
+        // We're waiting for transformation to "******"
+        PollingCheck.waitFor(TIMEOUT, () -> mTransformedText.toString()
+                .equals("\u2022\u2022\u2022\u2022\u2022\u2022"));
 
         // set null
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setTransformationMethod(null);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setTransformationMethod(null));
         mInstrumentation.waitForIdleSync();
         assertNull(mTextView.getTransformationMethod());
     }
@@ -3031,20 +3407,20 @@
         drawables = mTextView.getCompoundDrawables();
 
         // drawableLeft
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.start),
+        WidgetTestUtils.assertEquals(TestUtils.getBitmap(mActivity, R.drawable.start),
                 ((BitmapDrawable) drawables[0]).getBitmap());
         // drawableTop
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.pass),
+        WidgetTestUtils.assertEquals(TestUtils.getBitmap(mActivity, R.drawable.pass),
                 ((BitmapDrawable) drawables[1]).getBitmap());
         // drawableRight
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.failed),
+        WidgetTestUtils.assertEquals(TestUtils.getBitmap(mActivity, R.drawable.failed),
                 ((BitmapDrawable) drawables[2]).getBitmap());
         // drawableBottom
         assertNull(drawables[3]);
 
-        Drawable left = getDrawable(R.drawable.blue);
-        Drawable right = getDrawable(R.drawable.yellow);
-        Drawable top = getDrawable(R.drawable.red);
+        Drawable left = TestUtils.getDrawable(mActivity, R.drawable.blue);
+        Drawable right = TestUtils.getDrawable(mActivity, R.drawable.yellow);
+        Drawable top = TestUtils.getDrawable(mActivity, R.drawable.red);
 
         // using drawables directly
         mTextView.setCompoundDrawablesWithIntrinsicBounds(left, top, right, null);
@@ -3095,24 +3471,80 @@
         assertEquals(mTextView.getPaddingBottom(), mTextView.getCompoundPaddingBottom());
     }
 
+    @MediumTest
+    @UiThreadTest
+    public void testGetCompoundDrawablesRelative() {
+        // prepare textview
+        mTextView = new TextView(mActivity);
+
+        // prepare drawables
+        final Drawable start = TestUtils.getDrawable(mActivity, R.drawable.blue);
+        final Drawable end = TestUtils.getDrawable(mActivity, R.drawable.yellow);
+        final Drawable top = TestUtils.getDrawable(mActivity, R.drawable.red);
+        final Drawable bottom = TestUtils.getDrawable(mActivity, R.drawable.black);
+        assertNotNull(start);
+        assertNotNull(end);
+        assertNotNull(top);
+        assertNotNull(bottom);
+
+        Drawable[] drawables = mTextView.getCompoundDrawablesRelative();
+        assertNotNull(drawables);
+        assertEquals(4, drawables.length);
+        assertNull(drawables[0]);
+        assertNull(drawables[1]);
+        assertNull(drawables[2]);
+        assertNull(drawables[3]);
+
+        mTextView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+        mTextView.setCompoundDrawablesRelative(start, top, end, bottom);
+        drawables = mTextView.getCompoundDrawablesRelative();
+
+        assertNotNull(drawables);
+        assertEquals(4, drawables.length);
+        assertSame(start, drawables[0]);
+        assertSame(top, drawables[1]);
+        assertSame(end, drawables[2]);
+        assertSame(bottom, drawables[3]);
+
+        mTextView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+        mTextView.setCompoundDrawablesRelative(start, top, end, bottom);
+        drawables = mTextView.getCompoundDrawablesRelative();
+
+        assertNotNull(drawables);
+        assertEquals(4, drawables.length);
+        assertSame(start, drawables[0]);
+        assertSame(top, drawables[1]);
+        assertSame(end, drawables[2]);
+        assertSame(bottom, drawables[3]);
+
+        mTextView.setCompoundDrawablesRelative(null, null, null, null);
+        drawables = mTextView.getCompoundDrawablesRelative();
+
+        assertNotNull(drawables);
+        assertEquals(4, drawables.length);
+        assertNull(drawables[0]);
+        assertNull(drawables[1]);
+        assertNull(drawables[2]);
+        assertNull(drawables[3]);
+    }
+
+    @MediumTest
     public void testSingleLine() {
         final TextView textView = new TextView(mActivity);
         setSpannableText(textView, "This is a really long sentence"
                 + " which can not be placed in one line on the screen.");
 
         // Narrow layout assures that the text will get wrapped.
-        FrameLayout innerLayout = new FrameLayout(mActivity);
+        final FrameLayout innerLayout = new FrameLayout(mActivity);
         innerLayout.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
         innerLayout.addView(textView);
 
         final FrameLayout layout = new FrameLayout(mActivity);
         layout.addView(innerLayout);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(layout);
-                textView.setSingleLine(true);
-            }
+        mActivity.runOnUiThread(() -> {
+            mActivity.setContentView(layout);
+            textView.setSingleLine(true);
         });
         mInstrumentation.waitForIdleSync();
 
@@ -3127,11 +3559,7 @@
             singleLineHeight = textView.getLayout().getHeight();
         }
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                textView.setSingleLine(false);
-            }
-        });
+        mActivity.runOnUiThread(() -> textView.setSingleLine(false));
         mInstrumentation.waitForIdleSync();
         assertEquals(null, textView.getTransformationMethod());
 
@@ -3141,11 +3569,7 @@
         }
 
         // same behaviours as setSingLine(true)
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                textView.setSingleLine();
-            }
-        });
+        mActivity.runOnUiThread(textView::setSingleLine);
         mInstrumentation.waitForIdleSync();
         assertEquals(SingleLineTransformationMethod.getInstance(),
                 textView.getTransformationMethod());
@@ -3157,17 +3581,9 @@
     }
 
     @UiThreadTest
-    public void testSetMaxLines() {
+    public void testAccessMaxLines() {
         mTextView = findTextView(R.id.textview_text);
-
-        float[] widths = new float[LONG_TEXT.length()];
-        mTextView.getPaint().getTextWidths(LONG_TEXT, widths);
-        float totalWidth = 0.0f;
-        for (float f : widths) {
-            totalWidth += f;
-        }
-        final int stringWidth = (int) totalWidth;
-        mTextView.setWidth(stringWidth >> 2);
+        mTextView.setWidth((int) (mTextView.getPaint().measureText(LONG_TEXT) / 4));
         mTextView.setText(LONG_TEXT);
 
         final int maxLines = 2;
@@ -3176,23 +3592,11 @@
         mTextView.setMaxLines(maxLines);
         mTextView.requestLayout();
 
+        assertEquals(2, mTextView.getMaxLines());
+        assertEquals(-1, mTextView.getMaxHeight());
         assertTrue(mTextView.getHeight() <= maxLines * mTextView.getLineHeight());
     }
 
-    public int calculateTextWidth(String text) {
-        mTextView = findTextView(R.id.textview_text);
-
-        // Set the TextView width as the half of the whole text.
-        float[] widths = new float[text.length()];
-        mTextView.getPaint().getTextWidths(text, widths);
-        float textfieldWidth = 0.0f;
-        for (int i = 0; i < text.length(); ++i) {
-            textfieldWidth += widths[i];
-        }
-        return (int)textfieldWidth;
-
-    }
-
     @UiThreadTest
     public void testHyphenationNotHappen_frequencyNone() {
         final int[] BREAK_STRATEGIES = {
@@ -3204,7 +3608,8 @@
         for (int breakStrategy : BREAK_STRATEGIES) {
             for (int charWidth = 10; charWidth < 120; charWidth += 5) {
                 // Change the text view's width to charWidth width.
-                mTextView.setWidth(calculateTextWidth(LONG_TEXT.substring(0, charWidth)));
+                final String substring = LONG_TEXT.substring(0, charWidth);
+                mTextView.setWidth((int) Math.ceil(mTextView.getPaint().measureText(substring)));
 
                 mTextView.setText(LONG_TEXT);
                 mTextView.setBreakStrategy(breakStrategy);
@@ -3238,7 +3643,8 @@
         for (int hyphenationFrequency: HYPHENATION_FREQUENCIES) {
             for (int charWidth = 10; charWidth < 120; charWidth += 5) {
                 // Change the text view's width to charWidth width.
-                mTextView.setWidth(calculateTextWidth(LONG_TEXT.substring(0, charWidth)));
+                final String substring = LONG_TEXT.substring(0, charWidth);
+                mTextView.setWidth((int) Math.ceil(mTextView.getPaint().measureText(substring)));
 
                 mTextView.setText(LONG_TEXT);
                 mTextView.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
@@ -3269,17 +3675,20 @@
         mTextView.setMaxLines(-1);
     }
 
-    public void testSetMinLines() {
+    public void testAccessMinLines() {
         mTextView = findTextView(R.id.textview_text);
         setWidth(mTextView.getWidth() >> 3);
-        int originalHeight = mTextView.getHeight();
         int originalLines = mTextView.getLineCount();
 
         setMinLines(originalLines - 1);
         assertTrue((originalLines - 1) * mTextView.getLineHeight() <= mTextView.getHeight());
+        assertEquals(originalLines - 1, mTextView.getMinLines());
+        assertEquals(-1, mTextView.getMinHeight());
 
         setMinLines(originalLines + 1);
         assertTrue((originalLines + 1) * mTextView.getLineHeight() <= mTextView.getHeight());
+        assertEquals(originalLines + 1, mTextView.getMinLines());
+        assertEquals(-1, mTextView.getMinHeight());
     }
 
     public void testSetLines() {
@@ -3310,7 +3719,7 @@
         assertEquals(0, mTextView.getExtendedPaddingTop());
 
         // After Set a Drawable
-        final Drawable top = getDrawable(R.drawable.red);
+        final Drawable top = TestUtils.getDrawable(mActivity, R.drawable.red);
         top.setBounds(0, 0, 100, 10);
         mTextView.setCompoundDrawables(null, top, null, null);
         assertEquals(mTextView.getCompoundPaddingTop(), mTextView.getExtendedPaddingTop());
@@ -3329,7 +3738,7 @@
         assertEquals(0, mTextView.getExtendedPaddingBottom());
 
         // After Set a Drawable
-        final Drawable bottom = getDrawable(R.drawable.red);
+        final Drawable bottom = TestUtils.getDrawable(mActivity, R.drawable.red);
         bottom.setBounds(0, 0, 100, 10);
         mTextView.setCompoundDrawables(null, null, null, bottom);
         assertEquals(mTextView.getCompoundPaddingBottom(), mTextView.getExtendedPaddingBottom());
@@ -3347,14 +3756,12 @@
         assertEquals(0, mTextView.getTotalPaddingTop());
 
         // After Set a Drawable
-        final Drawable top = getDrawable(R.drawable.red);
+        final Drawable top = TestUtils.getDrawable(mActivity, R.drawable.red);
         top.setBounds(0, 0, 100, 10);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setCompoundDrawables(null, top, null, null);
-                mTextView.setLines(mTextView.getLineCount() - 1);
-                mTextView.setGravity(Gravity.BOTTOM);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setCompoundDrawables(null, top, null, null);
+            mTextView.setLines(mTextView.getLineCount() - 1);
+            mTextView.setGravity(Gravity.BOTTOM);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(mTextView.getExtendedPaddingTop(), mTextView.getTotalPaddingTop());
@@ -3373,14 +3780,12 @@
         assertEquals(0, mTextView.getTotalPaddingBottom());
 
         // After Set a Drawable
-        final Drawable bottom = getDrawable(R.drawable.red);
+        final Drawable bottom = TestUtils.getDrawable(mActivity, R.drawable.red);
         bottom.setBounds(0, 0, 100, 10);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setCompoundDrawables(null, null, null, bottom);
-                mTextView.setLines(mTextView.getLineCount() - 1);
-                mTextView.setGravity(Gravity.CENTER_VERTICAL);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView.setCompoundDrawables(null, null, null, bottom);
+            mTextView.setLines(mTextView.getLineCount() - 1);
+            mTextView.setGravity(Gravity.CENTER_VERTICAL);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(mTextView.getExtendedPaddingBottom(), mTextView.getTotalPaddingBottom());
@@ -3402,7 +3807,7 @@
         assertEquals(0, mTextView.getTotalPaddingLeft());
 
         // After Set a Drawable
-        Drawable left = getDrawable(R.drawable.red);
+        Drawable left = TestUtils.getDrawable(mActivity, R.drawable.red);
         left.setBounds(0, 0, 10, 100);
         mTextView.setCompoundDrawables(left, null, null, null);
         mTextView.setGravity(Gravity.RIGHT);
@@ -3420,7 +3825,7 @@
         assertEquals(0, mTextView.getTotalPaddingRight());
 
         // After Set a Drawable
-        Drawable right = getDrawable(R.drawable.red);
+        Drawable right = TestUtils.getDrawable(mActivity, R.drawable.red);
         right.setBounds(0, 0, 10, 100);
         mTextView.setCompoundDrawables(null, null, right, null);
         mTextView.setGravity(Gravity.CENTER_HORIZONTAL);
@@ -3519,6 +3924,8 @@
                 mTextView.getCurrentHintTextColor());
         assertEquals(mActivity.getResources().getColor(R.drawable.blue),
                 mTextView.getLinkTextColors().getDefaultColor());
+        assertEquals(mActivity.getResources().getColor(R.drawable.yellow),
+                mTextView.getHighlightColor());
 
         mTextView.setTextAppearance(R.style.TextAppearance_Colors);
         assertEquals(mActivity.getResources().getColor(R.drawable.black),
@@ -3527,6 +3934,8 @@
                 mTextView.getCurrentHintTextColor());
         assertEquals(mActivity.getResources().getColor(R.drawable.yellow),
                 mTextView.getLinkTextColors().getDefaultColor());
+        assertEquals(mActivity.getResources().getColor(R.drawable.red),
+                mTextView.getHighlightColor());
 
         mTextView.setTextAppearance(R.style.TextAppearance_NotColors);
         assertEquals(17f, mTextView.getTextSize(), 0.01f);
@@ -3609,11 +4018,10 @@
     }
 
     public void testDrawableStateChanged() {
-        MockTextView textView = new MockTextView(mActivity);
-
-        textView.reset();
+        MockTextView textView = spy(new MockTextView(mActivity));
+        reset(textView);
         textView.refreshDrawableState();
-        assertTrue(textView.hasCalledDrawableStateChanged());
+        verify(textView, times(1)).drawableStateChanged();
     }
 
     public void testGetDefaultEditable() {
@@ -3659,24 +4067,28 @@
 
         //Assign a new size to this view
         assertTrue(textView.setFrame(0, 0, 320, 480));
-        assertEquals(0, textView.getFrameLeft());
-        assertEquals(0, textView.getFrameTop());
-        assertEquals(320, textView.getFrameRight());
-        assertEquals(480, textView.getFrameBottom());
+        assertEquals(0, textView.getLeft());
+        assertEquals(0, textView.getTop());
+        assertEquals(320, textView.getRight());
+        assertEquals(480, textView.getBottom());
 
         //Assign a same size to this view
         assertFalse(textView.setFrame(0, 0, 320, 480));
 
         //negative input
         assertTrue(textView.setFrame(-1, -1, -1, -1));
-        assertEquals(-1, textView.getFrameLeft());
-        assertEquals(-1, textView.getFrameTop());
-        assertEquals(-1, textView.getFrameRight());
-        assertEquals(-1, textView.getFrameBottom());
+        assertEquals(-1, textView.getLeft());
+        assertEquals(-1, textView.getTop());
+        assertEquals(-1, textView.getRight());
+        assertEquals(-1, textView.getBottom());
     }
 
     public void testMarquee() {
-        final MockTextView textView = new MockTextView(mActivity);
+        // Both are pointing to the same object. This works around current limitation in CTS
+        // coverage report tool for properly reporting coverage of base class method calls.
+        final MockTextView mockTextView = new MockTextView(mActivity);
+        final TextView textView = mockTextView;
+
         textView.setText(LONG_TEXT);
         textView.setSingleLine();
         textView.setEllipsize(TruncateAt.MARQUEE);
@@ -3688,11 +4100,7 @@
         // make the fading to be shown
         textView.setHorizontalFadingEdgeEnabled(true);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(layout);
-            }
-        });
+        mActivity.runOnUiThread(() -> mActivity.setContentView(layout));
         mInstrumentation.waitForIdleSync();
 
         TestSelectedRunnable runnable = new TestSelectedRunnable(textView) {
@@ -3708,23 +4116,15 @@
 
         // wait for the marquee to run
         // fading is shown on both sides if the marquee runs for a while
-        new PollingCheck(TIMEOUT) {
-            @Override
-            protected boolean check() {
-                return textView.getLeftFadingEdgeStrength() > 0.0f
-                        && textView.getRightFadingEdgeStrength() > 0.0f;
-            }
-        }.run();
+        PollingCheck.waitFor(TIMEOUT, () -> mockTextView.getLeftFadingEdgeStrength() > 0.0f
+                && mockTextView.getRightFadingEdgeStrength() > 0.0f);
 
         // wait for left marquee to fully apply
-        new PollingCheck(TIMEOUT) {
-            @Override
-            protected boolean check() {
-                return textView.getLeftFadingEdgeStrength() > 0.99f;
-            }
-        }.run();
+        PollingCheck.waitFor(TIMEOUT, () -> mockTextView.getLeftFadingEdgeStrength() > 0.99f);
+
         assertFalse(runnable.getIsSelected1());
         assertTrue(runnable.getIsSelected2());
+        assertEquals(-1, textView.getMarqueeRepeatLimit());
 
         runnable = new TestSelectedRunnable(textView) {
             public void run() {
@@ -3741,27 +4141,28 @@
         mInstrumentation.waitForIdleSync();
         assertTrue(runnable.getIsSelected1());
         assertFalse(runnable.getIsSelected2());
-        assertEquals(0.0f, textView.getLeftFadingEdgeStrength(), 0.01f);
-        assertTrue(textView.getRightFadingEdgeStrength() > 0.0f);
+        assertEquals(0.0f, mockTextView.getLeftFadingEdgeStrength(), 0.01f);
+        assertTrue(mockTextView.getRightFadingEdgeStrength() > 0.0f);
+        assertEquals(0, textView.getMarqueeRepeatLimit());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                textView.setGravity(Gravity.RIGHT);
-            }
-        });
+        mActivity.runOnUiThread(() -> textView.setGravity(Gravity.RIGHT));
         mInstrumentation.waitForIdleSync();
-        assertTrue(textView.getLeftFadingEdgeStrength() > 0.0f);
-        assertEquals(0.0f, textView.getRightFadingEdgeStrength(), 0.01f);
+        assertTrue(mockTextView.getLeftFadingEdgeStrength() > 0.0f);
+        assertEquals(0.0f, mockTextView.getRightFadingEdgeStrength(), 0.01f);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                textView.setGravity(Gravity.CENTER_HORIZONTAL);
-            }
-        });
+        mActivity.runOnUiThread(() -> textView.setGravity(Gravity.CENTER_HORIZONTAL));
         mInstrumentation.waitForIdleSync();
         // there is no left fading (Is it correct?)
-        assertEquals(0.0f, textView.getLeftFadingEdgeStrength(), 0.01f);
-        assertTrue(textView.getRightFadingEdgeStrength() > 0.0f);
+        assertEquals(0.0f, mockTextView.getLeftFadingEdgeStrength(), 0.01f);
+        assertTrue(mockTextView.getRightFadingEdgeStrength() > 0.0f);
+    }
+
+    @MediumTest
+    public void testGetMarqueeRepeatLimit() {
+        final TextView textView = new TextView(mActivity);
+
+        textView.setMarqueeRepeatLimit(10);
+        assertEquals(10, textView.getMarqueeRepeatLimit());
     }
 
     public void testOnKeyMultiple() {
@@ -3954,7 +4355,7 @@
     public void testVerifyDrawable() {
         MockTextView textView = new MockTextView(mActivity);
 
-        Drawable d = getDrawable(R.drawable.pass);
+        Drawable d = TestUtils.getDrawable(mActivity, R.drawable.pass);
         assertFalse(textView.verifyDrawable(d));
 
         textView.setCompoundDrawables(null, d, null, null);
@@ -3975,14 +4376,16 @@
     public void testSetOnEditorActionListener() {
         mTextView = findTextView(R.id.textview_text);
 
-        MockOnEditorActionListener listener = new MockOnEditorActionListener();
-        assertFalse(listener.isOnEditorActionCalled());
+        final TextView.OnEditorActionListener mockOnEditorActionListener =
+                mock(TextView.OnEditorActionListener.class);
+        verifyZeroInteractions(mockOnEditorActionListener);
 
-        mTextView.setOnEditorActionListener(listener);
-        assertFalse(listener.isOnEditorActionCalled());
+        mTextView.setOnEditorActionListener(mockOnEditorActionListener);
+        verifyZeroInteractions(mockOnEditorActionListener);
 
         mTextView.onEditorAction(EditorInfo.IME_ACTION_DONE);
-        assertTrue(listener.isOnEditorActionCalled());
+        verify(mockOnEditorActionListener, times(1)).onEditorAction(mTextView,
+                EditorInfo.IME_ACTION_DONE, null);
     }
 
     public void testAccessImeOptions() {
@@ -4091,48 +4494,30 @@
         mTextView = findTextView(R.id.textview_text);
 
         // not a spannable text
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertFalse(mTextView.moveCursorToVisibleOffset());
-            }
-        });
+        runTestOnUiThread(() -> assertFalse(mTextView.moveCursorToVisibleOffset()));
         mInstrumentation.waitForIdleSync();
 
         // a selection range
         final String spannableText = "text";
         mTextView = new TextView(mActivity);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(spannableText, BufferType.SPANNABLE);
-            }
-        });
+        runTestOnUiThread(() -> mTextView.setText(spannableText, BufferType.SPANNABLE));
         mInstrumentation.waitForIdleSync();
         Selection.setSelection((Spannable) mTextView.getText(), 0, spannableText.length());
 
         assertEquals(0, mTextView.getSelectionStart());
         assertEquals(spannableText.length(), mTextView.getSelectionEnd());
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertFalse(mTextView.moveCursorToVisibleOffset());
-            }
-        });
+        runTestOnUiThread(() -> assertFalse(mTextView.moveCursorToVisibleOffset()));
         mInstrumentation.waitForIdleSync();
 
         // a spannable without range
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = findTextView(R.id.textview_text);
-                mTextView.setText(spannableText, BufferType.SPANNABLE);
-            }
+        runTestOnUiThread(() -> {
+            mTextView = findTextView(R.id.textview_text);
+            mTextView.setText(spannableText, BufferType.SPANNABLE);
         });
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertTrue(mTextView.moveCursorToVisibleOffset());
-            }
-        });
+        runTestOnUiThread(() -> assertTrue(mTextView.moveCursorToVisibleOffset()));
         mInstrumentation.waitForIdleSync();
     }
 
@@ -4141,29 +4526,71 @@
         assertFalse(mTextView.isInputMethodTarget());
 
         assertFalse(mTextView.isFocused());
-        runTestOnUiThread(new Runnable() {
-           @Override
-            public void run() {
-               mTextView.setFocusable(true);
-               mTextView.requestFocus();
-            }
-        });
+        runTestOnUiThread(() -> {
+            mTextView.setFocusable(true);
+            mTextView.requestFocus();
+         });
         mInstrumentation.waitForIdleSync();
         assertTrue(mTextView.isFocused());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mTextView.isInputMethodTarget();
-            }
-        }.run();
+        PollingCheck.waitFor(mTextView::isInputMethodTarget);
     }
 
-    public void testBeginEndBatchEdit() {
-        mTextView = findTextView(R.id.textview_text);
+    @MediumTest
+    public void testBeginEndBatchEditAreNotCalledForNonEditableText() {
+        final TextView mockTextView = spy(new TextView(mActivity));
 
-        mTextView.beginBatchEdit();
-        mTextView.endBatchEdit();
+        // TextView should not call onBeginBatchEdit or onEndBatchEdit during initialization
+        verify(mockTextView, never()).onBeginBatchEdit();
+        verify(mockTextView, never()).onEndBatchEdit();
+
+
+        mockTextView.beginBatchEdit();
+        // Since TextView doesn't support editing, the callbacks should not be called
+        verify(mockTextView, never()).onBeginBatchEdit();
+        verify(mockTextView, never()).onEndBatchEdit();
+
+        mockTextView.endBatchEdit();
+        // Since TextView doesn't support editing, the callbacks should not be called
+        verify(mockTextView, never()).onBeginBatchEdit();
+        verify(mockTextView, never()).onEndBatchEdit();
+    }
+
+    @MediumTest
+    public void testBeginEndBatchEditCallbacksAreCalledForEditableText() {
+        final TextView mockTextView = spy(new TextView(mActivity));
+
+        final FrameLayout layout = new FrameLayout(getActivity());
+        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        layout.addView(mockTextView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mActivity.runOnUiThread(() -> mActivity.setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        mActivity.runOnUiThread(() -> {
+            mockTextView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
+            mockTextView.setText("", BufferType.EDITABLE);
+            mockTextView.requestFocus();
+        });
+        mInstrumentation.waitForIdleSync();
+
+        reset(mockTextView);
+        assertTrue(mockTextView.hasFocus());
+        verify(mockTextView, never()).onBeginBatchEdit();
+        verify(mockTextView, never()).onEndBatchEdit();
+
+        mockTextView.beginBatchEdit();
+
+        verify(mockTextView, times(1)).onBeginBatchEdit();
+        verify(mockTextView, never()).onEndBatchEdit();
+
+        reset(mockTextView);
+        mockTextView.endBatchEdit();
+        verify(mockTextView, never()).onBeginBatchEdit();
+        verify(mockTextView, times(1)).onEndBatchEdit();
     }
 
     @UiThreadTest
@@ -4177,7 +4604,7 @@
 
     public void testCancelLongPress() {
         mTextView = findTextView(R.id.textview_text);
-        TouchUtils.longClickView(this, mTextView);
+        CtsTouchUtils.emulateLongClick(mInstrumentation, mTextView);
         mTextView.cancelLongPress();
     }
 
@@ -4203,7 +4630,7 @@
         MockTextView textView = new MockTextView(mActivity);
         assertEquals(0, textView.computeVerticalScrollExtent());
 
-        Drawable d = getDrawable(R.drawable.pass);
+        Drawable d = TestUtils.getDrawable(mActivity, R.drawable.pass);
         textView.setCompoundDrawables(null, d, null, d);
 
         assertEquals(0, textView.computeVerticalScrollExtent());
@@ -4221,23 +4648,21 @@
 
     public void testSelectAllJustAfterTap() {
         // Prepare an EditText with focus.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = new EditText(mActivity);
-                mActivity.setContentView(mTextView);
+        mActivity.runOnUiThread(() -> {
+            mTextView = new EditText(mActivity);
+            mActivity.setContentView(mTextView);
 
-                assertFalse(mTextView.didTouchFocusSelect());
-                mTextView.setFocusable(true);
-                mTextView.requestFocus();
-                assertTrue(mTextView.didTouchFocusSelect());
+            assertFalse(mTextView.didTouchFocusSelect());
+            mTextView.setFocusable(true);
+            mTextView.requestFocus();
+            assertTrue(mTextView.didTouchFocusSelect());
 
-                mTextView.setText("Hello, World.", BufferType.SPANNABLE);
-            }
+            mTextView.setText("Hello, World.", BufferType.SPANNABLE);
         });
         mInstrumentation.waitForIdleSync();
 
         // Tap the view to show InsertPointController.
-        TouchUtils.tapView(this, mTextView);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTextView);
         // bad workaround for waiting onStartInputView of LeanbackIme.apk done
         try {
             Thread.sleep(1000);
@@ -4246,11 +4671,7 @@
         }
 
         // Execute SelectAll context menu.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.onTextContextMenuItem(android.R.id.selectAll);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.onTextContextMenuItem(android.R.id.selectAll));
         mInstrumentation.waitForIdleSync();
 
         // The selection must be whole of the text contents.
@@ -4781,226 +5202,154 @@
 
     @UiThreadTest
     public void testDrawableResolution() {
-        final int LEFT = 0;
-        final int TOP = 1;
-        final int RIGHT = 2;
-        final int BOTTOM = 3;
-
-        TextViewCtsActivity activity = getActivity();
-
         // Case 1.1: left / right drawable defined in default LTR mode
-        TextView tv = (TextView) activity.findViewById(R.id.textview_drawable_1_1);
-        Drawable[] drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        TextView tv = (TextView) mActivity.findViewById(R.id.textview_drawable_1_1);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, -1, -1,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
         // Case 1.2: left / right drawable defined in default RTL mode
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_1_2);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_1_2);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, -1, -1,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
         // Case 2.1: start / end drawable defined in LTR mode
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_2_1);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_2_1);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
         // Case 2.2: start / end drawable defined in RTL mode
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_2_2);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_2_2);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_red, R.drawable.icon_blue,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
         // Case 3.1: left / right / start / end drawable defined in LTR mode
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_3_1);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_3_1);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
         // Case 3.2: left / right / start / end drawable defined in RTL mode
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_3_2);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_3_2);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_red, R.drawable.icon_blue,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
         // Case 4.1: start / end drawable defined in LTR mode inside a layout
         // that defines the layout direction
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_4_1);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_4_1);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
         // Case 4.2: start / end drawable defined in RTL mode inside a layout
         // that defines the layout direction
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_4_2);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_4_2);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_red, R.drawable.icon_blue,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
         // Case 5.1: left / right / start / end drawable defined in LTR mode inside a layout
         // that defines the layout direction
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_3_1);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_5_1);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
         // Case 5.2: left / right / start / end drawable defined in RTL mode inside a layout
         // that defines the layout direction
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_3_2);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_5_2);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_red, R.drawable.icon_blue,
+                R.drawable.icon_green, R.drawable.icon_yellow);
+        TestUtils.verifyCompoundDrawablesRelative(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
     }
 
     @UiThreadTest
     public void testDrawableResolution2() {
-        final int LEFT = 0;
-        final int TOP = 1;
-        final int RIGHT = 2;
-        final int BOTTOM = 3;
-
-        TextViewCtsActivity activity = getActivity();
-
         // Case 1.1: left / right drawable defined in default LTR mode
-        TextView tv = (TextView) activity.findViewById(R.id.textview_drawable_1_1);
-        Drawable[] drawables = tv.getCompoundDrawables();
+        TextView tv = (TextView) mActivity.findViewById(R.id.textview_drawable_1_1);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv.setCompoundDrawables(null, null,
+                TestUtils.getDrawable(mActivity, R.drawable.icon_yellow), null);
+        TestUtils.verifyCompoundDrawables(tv, -1, R.drawable.icon_yellow, -1, -1);
 
-        tv.setCompoundDrawables(null, null, getDrawable(R.drawable.icon_yellow), null);
-        drawables = tv.getCompoundDrawables();
+        tv = (TextView) mActivity.findViewById(R.id.textview_drawable_1_2);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_blue, R.drawable.icon_red,
+                R.drawable.icon_green, R.drawable.icon_yellow);
 
-        assertNull(drawables[LEFT]);
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        assertNull(drawables[TOP]);
-        assertNull(drawables[BOTTOM]);
+        tv.setCompoundDrawables(TestUtils.getDrawable(mActivity, R.drawable.icon_yellow), null,
+                null, null);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_yellow, -1, -1, -1);
 
-        tv = (TextView) activity.findViewById(R.id.textview_drawable_1_2);
-        drawables = tv.getCompoundDrawables();
+        tv = (TextView) mActivity.findViewById(R.id.textview_ltr);
+        TestUtils.verifyCompoundDrawables(tv, -1, -1, -1, -1);
 
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
-                ((BitmapDrawable) drawables[TOP]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
+        tv.setCompoundDrawables(TestUtils.getDrawable(mActivity, R.drawable.icon_blue), null,
+                TestUtils.getDrawable(mActivity, R.drawable.icon_red), null);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_blue, R.drawable.icon_red, -1, -1);
 
-        tv.setCompoundDrawables(getDrawable(R.drawable.icon_yellow), null, null, null);
-        drawables = tv.getCompoundDrawables();
+        tv.setCompoundDrawablesRelative(TestUtils.getDrawable(mActivity, R.drawable.icon_yellow),
+                null, null, null);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_yellow, -1, -1, -1);
+    }
 
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        assertNull(drawables[RIGHT]);
-        assertNull(drawables[TOP]);
-        assertNull(drawables[BOTTOM]);
+    public void testCompoundAndTotalPadding() {
+        final Resources res = mActivity.getResources();
+        final int drawablePadding = res.getDimensionPixelSize(R.dimen.textview_drawable_padding);
+        final int paddingLeft = res.getDimensionPixelSize(R.dimen.textview_padding_left);
+        final int paddingRight = res.getDimensionPixelSize(R.dimen.textview_padding_right);
+        final int paddingTop = res.getDimensionPixelSize(R.dimen.textview_padding_top);
+        final int paddingBottom = res.getDimensionPixelSize(R.dimen.textview_padding_bottom);
+        final int iconSize = TestUtils.dpToPx(mActivity, 32);
 
-        tv = (TextView) activity.findViewById(R.id.textview_ltr);
-        drawables = tv.getCompoundDrawables();
+        final TextView textViewLtr = (TextView) mActivity.findViewById(
+                R.id.textview_compound_drawable_ltr);
+        final int combinedPaddingLeftLtr = paddingLeft + drawablePadding + iconSize;
+        final int combinedPaddingRightLtr = paddingRight + drawablePadding + iconSize;
+        assertEquals(combinedPaddingLeftLtr, textViewLtr.getCompoundPaddingLeft());
+        assertEquals(combinedPaddingLeftLtr, textViewLtr.getCompoundPaddingStart());
+        assertEquals(combinedPaddingLeftLtr, textViewLtr.getTotalPaddingLeft());
+        assertEquals(combinedPaddingLeftLtr, textViewLtr.getTotalPaddingStart());
+        assertEquals(combinedPaddingRightLtr, textViewLtr.getCompoundPaddingRight());
+        assertEquals(combinedPaddingRightLtr, textViewLtr.getCompoundPaddingEnd());
+        assertEquals(combinedPaddingRightLtr, textViewLtr.getTotalPaddingRight());
+        assertEquals(combinedPaddingRightLtr, textViewLtr.getTotalPaddingEnd());
+        assertEquals(paddingTop + drawablePadding + iconSize,
+                textViewLtr.getCompoundPaddingTop());
+        assertEquals(paddingBottom + drawablePadding + iconSize,
+                textViewLtr.getCompoundPaddingBottom());
 
-        assertNull(drawables[LEFT]);
-        assertNull(drawables[RIGHT]);
-        assertNull(drawables[TOP]);
-        assertNull(drawables[BOTTOM]);
-
-        tv.setCompoundDrawables(getDrawable(R.drawable.icon_blue), null, getDrawable(R.drawable.icon_red), null);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
-                ((BitmapDrawable) drawables[RIGHT]).getBitmap());
-        assertNull(drawables[TOP]);
-        assertNull(drawables[BOTTOM]);
-
-        tv.setCompoundDrawablesRelative(getDrawable(R.drawable.icon_yellow), null, null, null);
-        drawables = tv.getCompoundDrawables();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        assertNull(drawables[RIGHT]);
-        assertNull(drawables[TOP]);
-        assertNull(drawables[BOTTOM]);
+        final TextView textViewRtl = (TextView) mActivity.findViewById(
+                R.id.textview_compound_drawable_rtl);
+        final int combinedPaddingLeftRtl = paddingLeft + drawablePadding + iconSize;
+        final int combinedPaddingRightRtl = paddingRight + drawablePadding + iconSize;
+        assertEquals(combinedPaddingLeftRtl, textViewRtl.getCompoundPaddingLeft());
+        assertEquals(combinedPaddingLeftRtl, textViewRtl.getCompoundPaddingEnd());
+        assertEquals(combinedPaddingLeftRtl, textViewRtl.getTotalPaddingLeft());
+        assertEquals(combinedPaddingLeftRtl, textViewRtl.getTotalPaddingEnd());
+        assertEquals(combinedPaddingRightRtl, textViewRtl.getCompoundPaddingRight());
+        assertEquals(combinedPaddingRightRtl, textViewRtl.getCompoundPaddingStart());
+        assertEquals(combinedPaddingRightRtl, textViewRtl.getTotalPaddingRight());
+        assertEquals(combinedPaddingRightRtl, textViewRtl.getTotalPaddingStart());
+        assertEquals(paddingTop + drawablePadding + iconSize,
+                textViewRtl.getCompoundPaddingTop());
+        assertEquals(paddingBottom + drawablePadding + iconSize,
+                textViewRtl.getCompoundPaddingBottom());
     }
 
     public void testSetGetBreakStrategy() {
@@ -5061,161 +5410,505 @@
 
     public void testSetAndGetCustomSelectionActionModeCallback() {
         final String text = "abcde";
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = new EditText(mActivity);
-                mActivity.setContentView(mTextView);
-                mTextView.setText(text, BufferType.SPANNABLE);
-                mTextView.setTextIsSelectable(true);
-                mTextView.requestFocus();
-                mTextView.setSelected(true);
-            }
+        mActivity.runOnUiThread(() -> {
+            mTextView = new EditText(mActivity);
+            mActivity.setContentView(mTextView);
+            mTextView.setText(text, BufferType.SPANNABLE);
+            mTextView.setTextIsSelectable(true);
+            mTextView.requestFocus();
+            mTextView.setSelected(true);
         });
         mInstrumentation.waitForIdleSync();
 
         // Check default value.
         assertNull(mTextView.getCustomSelectionActionModeCallback());
 
-        MockActionModeCallback callbackBlockActionMode = new MockActionModeCallback(false);
-        mTextView.setCustomSelectionActionModeCallback(callbackBlockActionMode);
-        assertEquals(callbackBlockActionMode,
+        final ActionMode.Callback mockActionModeCallback = mock(ActionMode.Callback.class);
+        when(mockActionModeCallback.onCreateActionMode(any(ActionMode.class), any(Menu.class))).
+                thenReturn(Boolean.FALSE);
+        mTextView.setCustomSelectionActionModeCallback(mockActionModeCallback);
+        assertEquals(mockActionModeCallback,
                 mTextView.getCustomSelectionActionModeCallback());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Set selection and try to start action mode.
-                final Bundle args = new Bundle();
-                args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
-                args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, text.length());
-                mTextView.performAccessibilityAction(
-                        AccessibilityNodeInfo.ACTION_SET_SELECTION, args);
-            }
+        mActivity.runOnUiThread(() -> {
+            // Set selection and try to start action mode.
+            final Bundle args = new Bundle();
+            args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
+            args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, text.length());
+            mTextView.performAccessibilityAction(
+                    AccessibilityNodeInfo.ACTION_SET_SELECTION, args);
         });
         mInstrumentation.waitForIdleSync();
 
-        assertEquals(1, callbackBlockActionMode.getCreateCount());
+        verify(mockActionModeCallback, times(1)).onCreateActionMode(
+                any(ActionMode.class), any(Menu.class));
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Remove selection and stop action mode.
-                mTextView.onTextContextMenuItem(android.R.id.copy);
-            }
+        mActivity.runOnUiThread(() -> {
+            // Remove selection and stop action mode.
+            mTextView.onTextContextMenuItem(android.R.id.copy);
         });
         mInstrumentation.waitForIdleSync();
 
         // Action mode was blocked.
-        assertEquals(0, callbackBlockActionMode.getDestroyCount());
+        verify(mockActionModeCallback, never()).onDestroyActionMode(any(ActionMode.class));
 
-        // Overwrite callback.
-        MockActionModeCallback callbackStartActionMode = new MockActionModeCallback(true);
-        mTextView.setCustomSelectionActionModeCallback(callbackStartActionMode);
-        assertEquals(callbackStartActionMode, mTextView.getCustomSelectionActionModeCallback());
+        // Reset and reconfigure callback.
+        reset(mockActionModeCallback);
+        when(mockActionModeCallback.onCreateActionMode(any(ActionMode.class), any(Menu.class))).
+                thenReturn(Boolean.TRUE);
+        assertEquals(mockActionModeCallback, mTextView.getCustomSelectionActionModeCallback());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Set selection and try to start action mode.
-                final Bundle args = new Bundle();
-                args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
-                args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, text.length());
-                mTextView.performAccessibilityAction(
-                        AccessibilityNodeInfo.ACTION_SET_SELECTION, args);
+        mActivity.runOnUiThread(() -> {
+            // Set selection and try to start action mode.
+            final Bundle args = new Bundle();
+            args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
+            args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, text.length());
+            mTextView.performAccessibilityAction(
+                    AccessibilityNodeInfo.ACTION_SET_SELECTION, args);
 
-            }
         });
         mInstrumentation.waitForIdleSync();
 
-        assertEquals(1, callbackStartActionMode.getCreateCount());
+        verify(mockActionModeCallback, times(1)).onCreateActionMode(
+                any(ActionMode.class), any(Menu.class));
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Remove selection and stop action mode.
-                mTextView.onTextContextMenuItem(android.R.id.copy);
-            }
+        mActivity.runOnUiThread(() -> {
+            // Remove selection and stop action mode.
+            mTextView.onTextContextMenuItem(android.R.id.copy);
         });
         mInstrumentation.waitForIdleSync();
 
         // Action mode was started
-        assertEquals(1, callbackStartActionMode.getDestroyCount());
+        verify(mockActionModeCallback, times(1)).onDestroyActionMode(any(ActionMode.class));
     }
 
-    public void testSetAndGetCustomInseltionActionMode() {
+    @UiThreadTest
+    public void testSetAndGetCustomInsertionActionMode() {
         initTextViewForTyping();
         // Check default value.
         assertNull(mTextView.getCustomInsertionActionModeCallback());
 
-        MockActionModeCallback callback = new MockActionModeCallback(false);
-        mTextView.setCustomInsertionActionModeCallback(callback);
-        assertEquals(callback, mTextView.getCustomInsertionActionModeCallback());
+        final ActionMode.Callback mockActionModeCallback = mock(ActionMode.Callback.class);
+        when(mockActionModeCallback.onCreateActionMode(any(ActionMode.class), any(Menu.class))).
+                thenReturn(Boolean.FALSE);
+        mTextView.setCustomInsertionActionModeCallback(mockActionModeCallback);
+        assertEquals(mockActionModeCallback, mTextView.getCustomInsertionActionModeCallback());
         // TODO(Bug: 22033189): Tests the set callback is actually used.
     }
 
-    private static class MockActionModeCallback implements ActionMode.Callback {
-        private int mCreateCount = 0;
-        private int mDestroyCount = 0;
-        private final boolean mAllowToStartActionMode;
+    public void testTextShadows() {
+        final TextView textViewWithConfiguredShadow =
+                (TextView) mActivity.findViewById(R.id.textview_with_shadow);
+        assertEquals(1.0f, textViewWithConfiguredShadow.getShadowDx());
+        assertEquals(2.0f, textViewWithConfiguredShadow.getShadowDy());
+        assertEquals(3.0f, textViewWithConfiguredShadow.getShadowRadius());
+        assertEquals(Color.GREEN, textViewWithConfiguredShadow.getShadowColor());
 
-        public MockActionModeCallback(boolean allowToStartActionMode) {
-            mAllowToStartActionMode = allowToStartActionMode;
-        }
+        final TextView textView = (TextView) mActivity.findViewById(R.id.textview_text);
+        assertEquals(0.0f, textView.getShadowDx());
+        assertEquals(0.0f, textView.getShadowDy());
+        assertEquals(0.0f, textView.getShadowRadius());
 
-        public int getCreateCount() {
-            return mCreateCount;
-        }
+        mActivity.runOnUiThread(() -> textView.setShadowLayer(5.0f, 3.0f, 4.0f, Color.RED));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(3.0f, textView.getShadowDx());
+        assertEquals(4.0f, textView.getShadowDy());
+        assertEquals(5.0f, textView.getShadowRadius());
+        assertEquals(Color.RED, textView.getShadowColor());
+    }
 
-        public int getDestroyCount() {
-            return mDestroyCount;
+    public void testFontFeatureSettings() {
+        final TextView textView = (TextView) mActivity.findViewById(R.id.textview_text);
+        assertTrue(TextUtils.isEmpty(textView.getFontFeatureSettings()));
+
+        mActivity.runOnUiThread(() -> textView.setFontFeatureSettings("smcp"));
+        mInstrumentation.waitForIdleSync();
+        assertEquals("smcp", textView.getFontFeatureSettings());
+
+        mActivity.runOnUiThread(() -> textView.setFontFeatureSettings("frac"));
+        mInstrumentation.waitForIdleSync();
+        assertEquals("frac", textView.getFontFeatureSettings());
+    }
+
+    private static class SoftInputResultReceiver extends ResultReceiver {
+        private boolean mIsDone;
+        private int mResultCode;
+
+        public SoftInputResultReceiver(Handler handler) {
+            super(handler);
         }
 
         @Override
-        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
-            return false;
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+            mResultCode = resultCode;
+            mIsDone = true;
         }
 
-        @Override
-        public void onDestroyActionMode(ActionMode mode) {
-            mDestroyCount++;
-        }
-
-        @Override
-        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-            mCreateCount++;
-            return mAllowToStartActionMode;
-        }
-
-        @Override
-        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-            return false;
-        }
-    };
-
-    private static class MockOnEditorActionListener implements OnEditorActionListener {
-        private boolean isOnEditorActionCalled;
-
-        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-            isOnEditorActionCalled = true;
-            return true;
-        }
-
-        public boolean isOnEditorActionCalled() {
-            return isOnEditorActionCalled;
+        public void reset() {
+            mIsDone = false;
         }
     }
 
-    private void layout(final TextView textView) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(textView);
-            }
+    public void testAccessShowSoftInputOnFocus() {
+        if (!mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) {
+            return;
+        }
+
+        // Scroll down to our EditText
+        final ScrollView scrollView = (ScrollView) mActivity.findViewById(R.id.scroller);
+        mTextView = findTextView(R.id.editview_text);
+        mActivity.runOnUiThread(() -> scrollView.fullScroll(View.FOCUS_DOWN));
+        mInstrumentation.waitForIdleSync();
+
+        // Mark it to show soft input on focus
+        mActivity.runOnUiThread(() -> mTextView.setShowSoftInputOnFocus(true));
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mTextView.getShowSoftInputOnFocus());
+
+        // And emulate click on it
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTextView);
+
+        // Verify that input method manager is active and accepting text
+        final InputMethodManager imManager = (InputMethodManager) mActivity
+                .getSystemService(Context.INPUT_METHOD_SERVICE);
+        PollingCheck.waitFor(imManager::isActive);
+        assertTrue(imManager.isAcceptingText());
+        assertTrue(imManager.isActive(mTextView));
+
+        // Since there is no API to check that soft input is showing, we're going to ask
+        // the input method manager to show soft input, passing our custom result receiver.
+        // We're expecting to get UNCHANGED_SHOWN, indicating that the soft input was already
+        // showing before showSoftInput was called.
+        SoftInputResultReceiver receiver = new SoftInputResultReceiver(mHandler);
+        imManager.showSoftInput(mTextView, 0, receiver);
+        PollingCheck.waitFor(() -> receiver.mIsDone);
+        assertEquals(InputMethodManager.RESULT_UNCHANGED_SHOWN, receiver.mResultCode);
+
+        // Close soft input
+        sendKeys(KeyEvent.KEYCODE_BACK);
+
+        // Reconfigure our edit text to not show soft input on focus
+        mActivity.runOnUiThread(() -> mTextView.setShowSoftInputOnFocus(false));
+        mInstrumentation.waitForIdleSync();
+        assertFalse(mTextView.getShowSoftInputOnFocus());
+
+        // Emulate click on it
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTextView);
+
+        // Ask input method manager to show soft input again. This time we're expecting to get
+        // SHOWN, indicating that the soft input was not showing before showSoftInput was called.
+        receiver.reset();
+        imManager.showSoftInput(mTextView, 0, receiver);
+        PollingCheck.waitFor(() -> receiver.mIsDone);
+        assertEquals(InputMethodManager.RESULT_SHOWN, receiver.mResultCode);
+
+        // Close soft input
+        sendKeys(KeyEvent.KEYCODE_BACK);
+    }
+
+    public void testIsSuggestionsEnabled() {
+        mTextView = findTextView(R.id.textview_text);
+
+        // Anything without InputType.TYPE_CLASS_TEXT doesn't have suggestions enabled
+        mInstrumentation.runOnMainSync(() -> mTextView.setInputType(InputType.TYPE_CLASS_DATETIME));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(() -> mTextView.setInputType(InputType.TYPE_CLASS_PHONE));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(() -> mTextView.setInputType(InputType.TYPE_CLASS_NUMBER));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        // From this point our text view has InputType.TYPE_CLASS_TEXT
+
+        // Anything with InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS doesn't have suggestions enabled
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL |
+                                InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS |
+                                InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        // Otherwise suggestions are enabled for specific type variations enumerated in the
+        // documentation of TextView.isSuggestionsEnabled
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        // and not on any other type variation
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_FILTER));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PERSON_NAME));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PHONETIC));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT |
+                                InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT |
+                                InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mInstrumentation.runOnMainSync(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD));
+        assertFalse(mTextView.isSuggestionsEnabled());
+    }
+
+    public void testAccessLetterSpacing() {
+        mTextView = findTextView(R.id.textview_text);
+        assertEquals(0.0f, mTextView.getLetterSpacing());
+
+        final CharSequence text = mTextView.getText();
+        final int textLength = text.length();
+
+        // Get advance widths of each character at the default letter spacing
+        final float[] initialWidths = new float[textLength];
+        mTextView.getPaint().getTextWidths(text.toString(), initialWidths);
+
+        // Get advance widths of each character at letter spacing = 1.0f
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mTextView,
+                () -> mTextView.setLetterSpacing(1.0f));
+        assertEquals(1.0f, mTextView.getLetterSpacing());
+        final float[] singleWidths = new float[textLength];
+        mTextView.getPaint().getTextWidths(text.toString(), singleWidths);
+
+        // Get advance widths of each character at letter spacing = 2.0f
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mTextView,
+                () -> mTextView.setLetterSpacing(2.0f));
+        assertEquals(2.0f, mTextView.getLetterSpacing());
+        final float[] doubleWidths = new float[textLength];
+        mTextView.getPaint().getTextWidths(text.toString(), doubleWidths);
+
+        // Since letter spacing setter treats the parameter as EM units, and we don't have
+        // a way to convert EMs into pixels, go over the three arrays of advance widths and
+        // test that the extra advance width at letter spacing 2.0f is double the extra
+        // advance width at letter spacing 1.0f.
+        for (int i = 0; i < textLength; i++) {
+            float singleWidthDelta = singleWidths[i] - initialWidths[i];
+            float doubleWidthDelta = doubleWidths[i] - initialWidths[i];
+            assertEquals("At index " + i + " initial is " + initialWidths[i] +
+                ", single is " + singleWidths[i] + " and double is " + doubleWidths[i],
+                    singleWidthDelta * 2.0f, doubleWidthDelta, 0.05f);
+        }
+    }
+
+    public void testTextIsSelectableFocusAndOnClick() {
+        // Prepare a focusable TextView with an onClickListener attached.
+        final View.OnClickListener mockOnClickListener = mock(View.OnClickListener.class);
+        mActivity.runOnUiThread(() -> {
+            mTextView = new TextView(mActivity);
+            mTextView.setText("...text 11:11. some more text is in here...");
+            mTextView.setFocusable(true);
+            mTextView.setOnClickListener(mockOnClickListener);
+            mActivity.setContentView(mTextView);
         });
         mInstrumentation.waitForIdleSync();
+        assertTrue(mTextView.isFocusable());
+        assertFalse(mTextView.isTextSelectable());
+        assertFalse(mTextView.isFocusableInTouchMode());
+        assertFalse(mTextView.isFocused());
+        assertFalse(mTextView.isInTouchMode());
+
+        // First tap on the view triggers onClick() but does not focus the TextView.
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTextView);
+        assertTrue(mTextView.isInTouchMode());
+        assertFalse(mTextView.isFocused());
+        verify(mockOnClickListener, times(1)).onClick(mTextView);
+        // So does the second tap.
+        reset(mockOnClickListener);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTextView);
+        assertTrue(mTextView.isInTouchMode());
+        assertFalse(mTextView.isFocused());
+        verify(mockOnClickListener, times(1)).onClick(mTextView);
+
+        mActivity.runOnUiThread(() -> mTextView.setTextIsSelectable(true));
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mTextView.isFocusable());
+        assertTrue(mTextView.isTextSelectable());
+        assertTrue(mTextView.isFocusableInTouchMode());
+        assertFalse(mTextView.isFocused());
+
+        // First tap on the view focuses the TextView but does not trigger onClick().
+        reset(mockOnClickListener);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTextView);
+        assertTrue(mTextView.isInTouchMode());
+        assertTrue(mTextView.isFocused());
+        verify(mockOnClickListener, never()).onClick(mTextView);
+        // The second tap triggers onClick() and keeps the focus.
+        reset(mockOnClickListener);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTextView);
+        assertTrue(mTextView.isInTouchMode());
+        assertTrue(mTextView.isFocused());
+        verify(mockOnClickListener, times(1)).onClick(mTextView);
+    }
+
+    private void verifyGetOffsetForPosition(final int x, final int y) {
+        final int actual = mTextView.getOffsetForPosition(x, y);
+
+        final Layout layout = mTextView.getLayout();
+        if (layout == null) {
+            assertEquals("For [" + x + ", " + y + "]", -1, actual);
+            return;
+        }
+
+        // Get the line which corresponds to the Y position
+        final int line = layout.getLineForVertical(y + mTextView.getScrollY());
+        // Get the offset in that line that corresponds to the X position
+        final int expected = layout.getOffsetForHorizontal(line, x + mTextView.getScrollX());
+        assertEquals("For [" + x + ", " + y + "]", expected, actual);
+    }
+
+    public void testGetOffsetForPosition() {
+        mTextView = findTextView(R.id.textview_text);
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mTextView, () -> {
+            mTextView.setText(LONG_TEXT);
+            mTextView.setPadding(0, 0, 0, 0);
+        });
+
+        assertNotNull(mTextView.getLayout());
+        final int viewWidth = mTextView.getWidth();
+        final int viewHeight = mTextView.getHeight();
+        final int lineHeight = mTextView.getLineHeight();
+
+        verifyGetOffsetForPosition(0, 0);
+        verifyGetOffsetForPosition(0, viewHeight / 2);
+        verifyGetOffsetForPosition(viewWidth / 3, lineHeight / 2);
+        verifyGetOffsetForPosition(viewWidth / 2, viewHeight / 2);
+        verifyGetOffsetForPosition(viewWidth, viewHeight);
+    }
+
+    @UiThreadTest
+    public void testOnResolvePointerIcon() throws InterruptedException {
+        final TextView selectableTextView = findTextView(R.id.textview_pointer);
+        final MotionEvent event = createMouseHoverEvent(selectableTextView);
+
+        // A selectable view shows the I beam
+        selectableTextView.setTextIsSelectable(true);
+
+        assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT),
+                selectableTextView.onResolvePointerIcon(event, 0));
+        selectableTextView.setTextIsSelectable(false);
+
+        // A clickable view shows the hand
+        selectableTextView.setLinksClickable(true);
+        SpannableString builder = new SpannableString("hello world");
+        selectableTextView.setText(builder, BufferType.SPANNABLE);
+        Spannable text = (Spannable) selectableTextView.getText();
+        text.setSpan(
+                new ClickableSpan() {
+                    @Override
+                    public void onClick(View widget) {
+
+                    }
+                }, 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+        assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HAND),
+                selectableTextView.onResolvePointerIcon(event, 0));
+
+        // A selectable & clickable view shows hand
+        selectableTextView.setTextIsSelectable(true);
+
+        assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HAND),
+                selectableTextView.onResolvePointerIcon(event, 0));
+
+        // An editable view shows the I-beam
+        final TextView editableTextView = new EditText(mActivity);
+
+        assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT),
+                editableTextView.onResolvePointerIcon(event, 0));
+    }
+
+    private MotionEvent createMouseHoverEvent(View view) {
+        final int[] xy = new int[2];
+        view.getLocationOnScreen(xy);
+        final int viewWidth = view.getWidth();
+        final int viewHeight = view.getHeight();
+        float x = xy[0] + viewWidth / 2.0f;
+        float y = xy[1] + viewHeight / 2.0f;
+        long eventTime = SystemClock.uptimeMillis();
+        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[1];
+        pointerCoords[0] = new MotionEvent.PointerCoords();
+        pointerCoords[0].x = x;
+        pointerCoords[0].y = y;
+        final int[] pointerIds = new int[1];
+        pointerIds[0] = 0;
+        return MotionEvent.obtain(0, eventTime, MotionEvent.ACTION_HOVER_MOVE, 1, pointerIds,
+                pointerCoords, 0, 0, 0, 0, 0, InputDevice.SOURCE_MOUSE, 0);
+    }
+
+    private void layout(final TextView textView) {
+        mActivity.runOnUiThread(() -> mActivity.setContentView(textView));
+        mInstrumentation.waitForIdleSync();
     }
 
     private void layout(final int layoutId) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(layoutId);
-            }
-        });
+        mActivity.runOnUiThread(() -> mActivity.setContentView(layoutId));
         mInstrumentation.waitForIdleSync();
     }
 
@@ -5227,56 +5920,33 @@
         return findTextView(id).getAutoLinkMask();
     }
 
-    private Bitmap getBitmap(int resid) {
-        return ((BitmapDrawable) getDrawable(resid)).getBitmap();
-    }
-
-    private Drawable getDrawable(int resid) {
-        return mActivity.getResources().getDrawable(resid);
+    private void setMaxLines(final int lines) {
+        mActivity.runOnUiThread(() -> mTextView.setMaxLines(lines));
+        mInstrumentation.waitForIdleSync();
     }
 
     private void setMaxWidth(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMaxWidth(pixels);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setMaxWidth(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setMinWidth(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMinWidth(pixels);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setMinWidth(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setMaxHeight(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMaxHeight(pixels);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setMaxHeight(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setMinHeight(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMinHeight(pixels);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setMinHeight(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setMinLines(final int minlines) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMinLines(minlines);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setMinLines(minlines));
         mInstrumentation.waitForIdleSync();
     }
 
@@ -5288,83 +5958,47 @@
      * @param content the content
      */
     private void setSpannableText(final TextView tv, final String content) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                tv.setText(content, BufferType.SPANNABLE);
-            }
-        });
+        mActivity.runOnUiThread(() -> tv.setText(content, BufferType.SPANNABLE));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setLines(final int lines) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setLines(lines);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setLines(lines));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setHorizontallyScrolling(final boolean whether) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setHorizontallyScrolling(whether);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setHorizontallyScrolling(whether));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setWidth(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setWidth(pixels);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setWidth(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setHeight(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setHeight(pixels);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setHeight(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setMinEms(final int ems) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMinEms(ems);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setMinEms(ems));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setMaxEms(final int ems) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMaxEms(ems);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setMaxEms(ems));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setEms(final int ems) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setEms(ems);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setEms(ems));
         mInstrumentation.waitForIdleSync();
     }
 
     private void setLineSpacing(final float add, final float mult) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setLineSpacing(add, mult);
-            }
-        });
+        mActivity.runOnUiThread(() -> mTextView.setLineSpacing(add, mult));
         mInstrumentation.waitForIdleSync();
     }
 
@@ -5411,56 +6045,6 @@
         }
     }
 
-    private class MockEditableFactory extends Editable.Factory {
-        private boolean mhasCalledNewEditable;
-        private CharSequence mSource;
-
-        public boolean hasCalledNewEditable() {
-            return mhasCalledNewEditable;
-        }
-
-        public void reset() {
-            mhasCalledNewEditable = false;
-            mSource = null;
-        }
-
-        public CharSequence getSource() {
-            return mSource;
-        }
-
-        @Override
-        public Editable newEditable(CharSequence source) {
-            mhasCalledNewEditable = true;
-            mSource = source;
-            return super.newEditable(source);
-        }
-    }
-
-    private class MockSpannableFactory extends Spannable.Factory {
-        private boolean mHasCalledNewSpannable;
-        private CharSequence mSource;
-
-        public boolean hasCalledNewSpannable() {
-            return mHasCalledNewSpannable;
-        }
-
-        public void reset() {
-            mHasCalledNewSpannable = false;
-            mSource = null;
-        }
-
-        public CharSequence getSource() {
-            return mSource;
-        }
-
-        @Override
-        public Spannable newSpannable(CharSequence source) {
-            mHasCalledNewSpannable = true;
-            mSource = source;
-            return super.newSpannable(source);
-        }
-    }
-
     private static class MockTextWatcher implements TextWatcher {
         private boolean mHasCalledAfterTextChanged;
         private boolean mHasCalledBeforeTextChanged;
@@ -5498,70 +6082,6 @@
     }
 
     /**
-     * The listener interface for receiving mockOnLongClick events. The class
-     * that is interested in processing a mockOnLongClick event implements this
-     * interface, and the object created with that class is registered with a
-     * component using the component's
-     * <code>addMockOnLongClickListener<code> method. When
-     * the mockOnLongClick event occurs, that object's appropriate
-     * method is invoked.
-     *
-     * @see MockOnLongClickEvent
-     */
-    private static class MockOnLongClickListener implements OnLongClickListener {
-        private boolean mExpectedOnLongClickResult;
-        private boolean mHasLongClicked;
-
-        MockOnLongClickListener(boolean result) {
-            mExpectedOnLongClickResult = result;
-        }
-
-        public boolean hasLongClicked() {
-            return mHasLongClicked;
-        }
-
-        public boolean onLongClick(View v) {
-            mHasLongClicked = true;
-            return mExpectedOnLongClickResult;
-        }
-    }
-
-    /**
-     * The listener interface for receiving mockOnCreateContextMenu events. The
-     * class that is interested in processing a mockOnCreateContextMenu event
-     * implements this interface, and the object created with that class is
-     * registered with a component using the component's
-     * <code>addMockOnCreateContextMenuListener<code> method. When the
-     * mockOnCreateContextMenu event occurs, that object's appropriate method is
-     * invoked.
-     *
-     * @see MockOnCreateContextMenuEvent
-     */
-    private static class MockOnCreateContextMenuListener implements OnCreateContextMenuListener {
-        private boolean mIsMenuItemsBlank;
-        private boolean mHasCreatedContextMenu;
-
-        MockOnCreateContextMenuListener(boolean isBlank) {
-            this.mIsMenuItemsBlank = isBlank;
-        }
-
-        public boolean hasCreatedContextMenu() {
-            return mHasCreatedContextMenu;
-        }
-
-        public void reset() {
-            mHasCreatedContextMenu = false;
-        }
-
-        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
-            mHasCreatedContextMenu = true;
-            if (!mIsMenuItemsBlank) {
-                menu.add("menu item");
-            }
-        }
-    }
-
-    /**
      * A TextWatcher that converts the text to spaces whenever the text changes.
      */
     private static class ConvertToSpacesTextWatcher implements TextWatcher {
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/TimePickerCtsActivity.java
similarity index 68%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/TimePickerCtsActivity.java
index 481f5be..34fb8c0 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/TimePickerCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.TimePicker;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link TimePicker} test.
+ */
+public class TimePickerCtsActivity extends Activity {
+    /**
+     * Called when the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.timepicker);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
index 39554bb..43f63be 100644
--- a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
@@ -16,46 +16,54 @@
 
 package android.widget.cts;
 
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.cts.util.CtsKeyEventUtil;
+import android.cts.util.CtsTouchUtils;
 import android.os.Parcelable;
 import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
 import android.widget.TimePicker;
-import android.widget.TimePicker.OnTimeChangedListener;
+
+import java.util.ArrayList;
+import java.util.Collections;
 
 /**
  * Test {@link TimePicker}.
  */
-public class TimePickerTest extends ActivityInstrumentationTestCase2<CtsActivity> {
+@MediumTest
+public class TimePickerTest extends ActivityInstrumentationTestCase2<TimePickerCtsActivity> {
     private TimePicker mTimePicker;
-
     private Activity mActivity;
-
-    private Context mContext;
-
     private Instrumentation mInstrumentation;
 
     public TimePickerTest() {
-        super("android.widget.cts", CtsActivity.class);
+        super("android.widget.cts", TimePickerCtsActivity.class);
     }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
         mInstrumentation = getInstrumentation();
-        mContext = mInstrumentation.getTargetContext();
         mActivity = getActivity();
+        mTimePicker = (TimePicker) mActivity.findViewById(R.id.timepicker_clock);
     }
 
     public void testConstructors() {
         AttributeSet attrs =
-            mContext.getResources().getLayout(android.widget.cts.R.layout.timepicker);
+            mActivity.getResources().getLayout(android.widget.cts.R.layout.timepicker);
         assertNotNull(attrs);
 
-        new TimePicker(mContext);
+        new TimePicker(mActivity);
         try {
             new TimePicker(null);
             fail("did not throw NullPointerException when param context is null.");
@@ -63,29 +71,31 @@
             // expected
         }
 
-        new TimePicker(mContext, attrs);
+        new TimePicker(mActivity, attrs);
         try {
             new TimePicker(null, attrs);
             fail("did not throw NullPointerException when param context is null.");
         } catch (NullPointerException e) {
             // expected
         }
-        new TimePicker(mContext, null);
+        new TimePicker(mActivity, null);
 
-        new TimePicker(mContext, attrs, 0);
+        new TimePicker(mActivity, attrs, 0);
         try {
             new TimePicker(null, attrs, 0);
             fail("did not throw NullPointerException when param context is null.");
         } catch (NullPointerException e) {
             // expected
         }
-        new TimePicker(mContext, null, 0);
-        new TimePicker(mContext, attrs, 0);
-        new TimePicker(mContext, attrs, Integer.MIN_VALUE);
+        new TimePicker(mActivity, null, 0);
+        new TimePicker(mActivity, attrs, 0);
+        new TimePicker(mActivity, null, android.R.attr.timePickerStyle);
+        new TimePicker(mActivity, null, 0, android.R.style.Widget_Material_TimePicker);
+        new TimePicker(mActivity, null, 0, android.R.style.Widget_Material_Light_TimePicker);
     }
 
+    @UiThreadTest
     public void testSetEnabled() {
-        mTimePicker = new TimePicker(mContext);
         assertTrue(mTimePicker.isEnabled());
 
         mTimePicker.setEnabled(false);
@@ -96,49 +106,66 @@
     }
 
     public void testSetOnTimeChangedListener() {
-        int initialHour = 13;
-        int initialMinute = 50;
-        mTimePicker = new TimePicker(mContext);
+        // On time change listener is notified on every call to setCurrentHour / setCurrentMinute.
+        // We want to make sure that before we register our listener, we initialize the time picker
+        // to the time that is explicitly different from the values we'll be testing for in both
+        // hour and minute. Otherwise if the test happens to run at the time that ends in
+        // "minuteForTesting" minutes, we'll get two onTimeChanged callbacks with identical values.
+        final int initialHour = 10;
+        final int initialMinute = 38;
+        final int hourForTesting = 13;
+        final int minuteForTesting = 50;
 
-        MockOnTimeChangeListener listener = new MockOnTimeChangeListener();
-        mTimePicker.setOnTimeChangedListener(listener);
-        mTimePicker.setCurrentHour(Integer.valueOf(initialHour));
-        mTimePicker.setCurrentMinute(Integer.valueOf(initialMinute));
-        assertEquals(initialHour, listener.getNotifiedHourOfDay());
-        assertEquals(initialMinute, listener.getNotifiedMinute());
+        mInstrumentation.runOnMainSync(() -> {
+            mTimePicker.setHour(initialHour);
+            mTimePicker.setMinute(initialMinute);
+        });
+
+        // Now register the listener
+        TimePicker.OnTimeChangedListener mockOnTimeChangeListener =
+                mock(TimePicker.OnTimeChangedListener.class);
+        mTimePicker.setOnTimeChangedListener(mockOnTimeChangeListener);
+        mInstrumentation.runOnMainSync(() -> {
+                mTimePicker.setCurrentHour(Integer.valueOf(hourForTesting));
+                mTimePicker.setCurrentMinute(Integer.valueOf(minuteForTesting));
+        });
+        // We're expecting two onTimeChanged callbacks, one with new hour and one with new
+        // hour+minute
+        verify(mockOnTimeChangeListener, times(1)).onTimeChanged(
+                mTimePicker, hourForTesting, initialMinute);
+        verify(mockOnTimeChangeListener, times(1)).onTimeChanged(
+                mTimePicker, hourForTesting, minuteForTesting);
 
         // set the same hour as current
-        listener.reset();
-        mTimePicker.setCurrentHour(Integer.valueOf(initialHour));
-        assertFalse(listener.hasCalledOnTimeChanged());
+        reset(mockOnTimeChangeListener);
+        mInstrumentation.runOnMainSync(
+                () -> mTimePicker.setCurrentHour(Integer.valueOf(hourForTesting)));
+        verifyZeroInteractions(mockOnTimeChangeListener);
 
-        mTimePicker.setCurrentHour(Integer.valueOf(initialHour + 1));
-        assertTrue(listener.hasCalledOnTimeChanged());
-        assertEquals(initialHour + 1, listener.getNotifiedHourOfDay());
-        assertEquals(initialMinute, listener.getNotifiedMinute());
-        assertSame(mTimePicker, listener.getNotifiedView());
+        mInstrumentation.runOnMainSync(
+                () -> mTimePicker.setCurrentHour(Integer.valueOf(hourForTesting + 1)));
+        verify(mockOnTimeChangeListener, times(1)).onTimeChanged(
+                mTimePicker, hourForTesting + 1, minuteForTesting);
 
         // set the same minute as current
-        listener.reset();
-        mTimePicker.setCurrentMinute(initialMinute);
-        assertFalse(listener.hasCalledOnTimeChanged());
+        reset(mockOnTimeChangeListener);
+        mInstrumentation.runOnMainSync(() -> mTimePicker.setCurrentMinute(minuteForTesting));
+        verifyZeroInteractions(mockOnTimeChangeListener);
 
-        listener.reset();
-        mTimePicker.setCurrentMinute(initialMinute + 1);
-        assertTrue(listener.hasCalledOnTimeChanged());
-        assertEquals(initialHour + 1, listener.getNotifiedHourOfDay());
-        assertEquals(initialMinute + 1, listener.getNotifiedMinute());
-        assertSame(mTimePicker, listener.getNotifiedView());
+        reset(mockOnTimeChangeListener);
+        mInstrumentation.runOnMainSync(() -> mTimePicker.setCurrentMinute(minuteForTesting + 1));
+        verify(mockOnTimeChangeListener, times(1)).onTimeChanged(
+                mTimePicker, hourForTesting + 1, minuteForTesting + 1);
 
         // change time picker mode
-        listener.reset();
-        mTimePicker.setIs24HourView( !mTimePicker.is24HourView() );
-        assertFalse(listener.hasCalledOnTimeChanged());
+        reset(mockOnTimeChangeListener);
+        mInstrumentation.runOnMainSync(
+                () -> mTimePicker.setIs24HourView(!mTimePicker.is24HourView()));
+        verifyZeroInteractions(mockOnTimeChangeListener);
     }
 
+    @UiThreadTest
     public void testAccessCurrentHour() {
-        mTimePicker = new TimePicker(mContext);
-
         // AM/PM mode
         mTimePicker.setIs24HourView(false);
 
@@ -167,9 +194,8 @@
         assertEquals(Integer.valueOf(23), mTimePicker.getCurrentHour());
     }
 
+    @UiThreadTest
     public void testAccessHour() {
-        mTimePicker = new TimePicker(mContext);
-
         // AM/PM mode
         mTimePicker.setIs24HourView(false);
 
@@ -198,8 +224,8 @@
         assertEquals(23, mTimePicker.getHour());
     }
 
+    @UiThreadTest
     public void testAccessIs24HourView() {
-        mTimePicker = new TimePicker(mContext);
         assertFalse(mTimePicker.is24HourView());
 
         mTimePicker.setIs24HourView(true);
@@ -209,9 +235,8 @@
         assertFalse(mTimePicker.is24HourView());
     }
 
+    @UiThreadTest
     public void testAccessCurrentMinute() {
-        mTimePicker = new TimePicker(mContext);
-
         mTimePicker.setCurrentMinute(0);
         assertEquals(Integer.valueOf(0), mTimePicker.getCurrentMinute());
 
@@ -225,9 +250,8 @@
         assertEquals(Integer.valueOf(59), mTimePicker.getCurrentMinute());
     }
 
+    @UiThreadTest
     public void testAccessMinute() {
-        mTimePicker = new TimePicker(mContext);
-
         mTimePicker.setMinute(0);
         assertEquals(0, mTimePicker.getMinute());
 
@@ -242,13 +266,12 @@
     }
 
     public void testGetBaseline() {
-        mTimePicker = new TimePicker(mContext);
         assertEquals(-1, mTimePicker.getBaseline());
     }
 
     public void testOnSaveInstanceStateAndOnRestoreInstanceState() {
-        MyTimePicker source = new MyTimePicker(mContext);
-        MyTimePicker dest = new MyTimePicker(mContext);
+        MyTimePicker source = new MyTimePicker(mActivity);
+        MyTimePicker dest = new MyTimePicker(mActivity);
         int expectHour = (dest.getCurrentHour() + 10) % 24;
         int expectMinute = (dest.getCurrentMinute() + 10) % 60;
         source.setCurrentHour(expectHour);
@@ -261,43 +284,283 @@
         assertEquals(Integer.valueOf(expectMinute), dest.getCurrentMinute());
     }
 
-    private class MockOnTimeChangeListener implements OnTimeChangedListener {
-        private TimePicker mNotifiedView;
+    public void testKeyboardTabTraversal_modeClock() {
+        mTimePicker = (TimePicker) mActivity.findViewById(R.id.timepicker_clock);
 
-        private boolean mHasCalledOnTimeChanged;
+        mInstrumentation.runOnMainSync(() -> mTimePicker.setIs24HourView(false));
+        mInstrumentation.waitForIdleSync();
+        verifyTimePickerKeyboardTraversal(
+                true /* goForward */,
+                false /* is24HourView */,
+                false /* isSpinner */);
+        verifyTimePickerKeyboardTraversal(
+                false /* goForward */,
+                false /* is24HourView */,
+                false /* isSpinner */);
 
-        private int mNotifiedHourOfDay;
+        mInstrumentation.runOnMainSync(() -> mTimePicker.setIs24HourView(true));
+        mInstrumentation.waitForIdleSync();
+        verifyTimePickerKeyboardTraversal(
+                true /* goForward */,
+                true /* is24HourView */,
+                false /* isSpinner */);
+        verifyTimePickerKeyboardTraversal(
+                false /* goForward */,
+                true /* is24HourView */,
+                false /* isSpinner */);
+    }
 
-        private int mNotifiedMinute;;
+    public void testKeyboardTabTraversal_modeSpinner() {
+        mTimePicker = (TimePicker) mActivity.findViewById(R.id.timepicker_spinner);
 
-        public boolean hasCalledOnTimeChanged() {
-            return mHasCalledOnTimeChanged;
+        mInstrumentation.runOnMainSync(() -> mTimePicker.setIs24HourView(false));
+        mInstrumentation.waitForIdleSync();
+        verifyTimePickerKeyboardTraversal(
+                true /* goForward */,
+                false /* is24HourView */,
+                true /* isSpinner */);
+        verifyTimePickerKeyboardTraversal(
+                false /* goForward */,
+                false /* is24HourView */,
+                true /* isSpinner */);
+
+        mInstrumentation.runOnMainSync(() -> mTimePicker.setIs24HourView(true));
+        mInstrumentation.waitForIdleSync();
+        verifyTimePickerKeyboardTraversal(
+                true /* goForward */,
+                true /* is24HourView */,
+                true /* isSpinner */);
+        verifyTimePickerKeyboardTraversal(
+                false /* goForward */,
+                true /* is24HourView */,
+                true /* isSpinner */);
+    }
+
+    public void testKeyboardInputModeClockAmPm() {
+        final int initialHour = 6;
+        final int initialMinute = 59;
+        prepareForKeyboardInput(initialHour, initialMinute, false);
+
+        // Input valid hour.
+        assertEquals(initialHour, mTimePicker.getHour());
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTimePicker.getHourView());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_0);
+        assertEquals(10, mTimePicker.getHour());
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+
+        // Input valid minute.
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_4);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_3);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertEquals(43, mTimePicker.getMinute());
+        assertTrue(mTimePicker.getAmView().hasFocus());
+
+        // Accepting AM changes nothing.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_ENTER);
+        assertEquals(10, mTimePicker.getHour());
+        assertEquals(43, mTimePicker.getMinute());
+
+        // Focus PM radio.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertTrue(mTimePicker.getPmView().hasFocus());
+        // Still nothing has changed.
+        assertEquals(10, mTimePicker.getHour());
+        assertEquals(43, mTimePicker.getMinute());
+        // Select PM and verify the hour has changed.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_ENTER);
+        assertEquals(22, mTimePicker.getHour());
+        assertEquals(43, mTimePicker.getMinute());
+        // Set AM again.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        assertTrue(mTimePicker.getAmView().hasFocus());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_ENTER);
+        assertEquals(10, mTimePicker.getHour());
+
+        // Re-focus the hour view.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertTrue(mTimePicker.getHourView().hasFocus());
+
+        // Input an invalid value (larger than 12).
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_3);
+        // Force setting the hour by moving to minute.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        // After sending 1 and 3 only 1 is accepted.
+        assertEquals(1, mTimePicker.getHour());
+        assertEquals(43, mTimePicker.getMinute());
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        // The hour view still has focus.
+        assertTrue(mTimePicker.getHourView().hasFocus());
+
+        // This time send a valid hour (11).
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_1);
+        // The value is valid.
+        assertEquals(11, mTimePicker.getHour());
+        assertEquals(43, mTimePicker.getMinute());
+
+        verifyModeClockMinuteInput();
+    }
+
+    public void testKeyboardInputModeClock24H() {
+        final int initialHour = 6;
+        final int initialMinute = 59;
+        prepareForKeyboardInput(initialHour, initialMinute, true);
+
+        // Input valid hour.
+        assertEquals(initialHour, mTimePicker.getHour());
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTimePicker.getHourView());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_0);
+        assertEquals(10, mTimePicker.getHour());
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+
+        // Input valid minute.
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_4);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_3);
+        assertEquals(43, mTimePicker.getMinute());
+
+        // Re-focus the hour view.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        assertTrue(mTimePicker.getHourView().hasFocus());
+
+        // Input an invalid value (larger than 24).
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_2);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_5);
+        // Force setting the hour by moving to minute.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        // After sending 2 and 5 only 2 is accepted.
+        assertEquals(2, mTimePicker.getHour());
+        assertEquals(43, mTimePicker.getMinute());
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        // The hour view still has focus.
+        assertTrue(mTimePicker.getHourView().hasFocus());
+
+        // This time send a valid hour.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_2);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_3);
+        // The value is valid.
+        assertEquals(23, mTimePicker.getHour());
+        assertEquals(43, mTimePicker.getMinute());
+
+        verifyModeClockMinuteInput();
+    }
+
+    private void verifyModeClockMinuteInput() {
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+        // Send a invalid minute.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_6);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_7);
+        // Sent 6 and 7 but only 6 was valid.
+        assertEquals(6, mTimePicker.getMinute());
+        // No matter what other invalid values we send, the minute is unchanged and the focus is
+        // kept.
+        // 61 invalid.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_1);
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+        // 62 invalid.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_2);
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+        // 63 invalid.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_3);
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+        assertEquals(6, mTimePicker.getMinute());
+        // Refocus.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+
+        // In the end pass a valid minute.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_5);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_9);
+        assertEquals(59, mTimePicker.getMinute());
+    }
+
+    private void prepareForKeyboardInput(int initialHour, int initialMinute, boolean is24hFormat) {
+        mTimePicker = (TimePicker) mActivity.findViewById(R.id.timepicker_clock);
+        final View spinnerTimePicker = mActivity.findViewById(R.id.timepicker_spinner);
+
+        mInstrumentation.runOnMainSync(() -> {
+            // Remove the spinner TimePicker.
+            ((ViewGroup) spinnerTimePicker.getParent()).removeView(spinnerTimePicker);
+            mTimePicker.setIs24HourView(is24hFormat);
+            mTimePicker.setHour(initialHour);
+            mTimePicker.setMinute(initialMinute);
+            mTimePicker.requestFocus();
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void verifyTimePickerKeyboardTraversal(boolean goForward, boolean is24HourView,
+            boolean isSpinner) {
+        ArrayList<View> forwardViews = new ArrayList<>();
+        String summary = (goForward ? " forward " : " backward ")
+                + "traversal, is24HourView=" + is24HourView
+                + (isSpinner ? ", mode spinner" : ", mode clock");
+        assertNotNull("Unexpected NULL hour view for" + summary, mTimePicker.getHourView());
+        forwardViews.add(mTimePicker.getHourView());
+        assertNotNull("Unexpected NULL minute view for" + summary, mTimePicker.getMinuteView());
+        forwardViews.add(mTimePicker.getMinuteView());
+        if (!is24HourView) {
+            if (isSpinner) {
+                // The spinner mode only contains one view for inputting AM/PM.
+                assertNotNull("Unexpected NULL AM/PM view for" + summary, mTimePicker.getAmView());
+                forwardViews.add(mTimePicker.getAmView());
+            } else {
+                assertNotNull("Unexpected NULL AM view for" + summary, mTimePicker.getAmView());
+                forwardViews.add(mTimePicker.getAmView());
+                assertNotNull("Unexpected NULL PM view for" + summary, mTimePicker.getPmView());
+                forwardViews.add(mTimePicker.getPmView());
+            }
         }
 
-        public TimePicker getNotifiedView() {
-            return mNotifiedView;
+        if (!goForward) {
+            Collections.reverse(forwardViews);
         }
 
-        public int getNotifiedHourOfDay() {
-            return mNotifiedHourOfDay;
-        }
+        final int viewsSize = forwardViews.size();
+        for (int i = 0; i < viewsSize; i++) {
+            final View currentView = forwardViews.get(i);
+            String afterKeyCodeFormattedString = "";
+            int goForwardKeyCode = KeyEvent.KEYCODE_TAB;
+            int modifierKeyCodeToHold = KeyEvent.KEYCODE_SHIFT_LEFT;
 
-        public int getNotifiedMinute() {
-            return mNotifiedMinute;
-        }
+            if (i == 0) {
+                // Make sure we always start by focusing the 1st element in the list.
+                mInstrumentation.runOnMainSync(currentView::requestFocus);
+            } else {
+                if (goForward) {
+                    afterKeyCodeFormattedString = " after pressing="
+                            + KeyEvent.keyCodeToString(goForwardKeyCode);
+                } else {
+                    afterKeyCodeFormattedString = " after pressing="
+                            + KeyEvent.keyCodeToString(modifierKeyCodeToHold)
+                            + "+" + KeyEvent.keyCodeToString(goForwardKeyCode)  + " for" + summary;
+                }
+            }
 
-        public void reset() {
-            mNotifiedView = null;
-            mNotifiedHourOfDay = 0;
-            mNotifiedMinute = 0;
-            mHasCalledOnTimeChanged = false;
-        }
+            assertTrue("View='" + currentView + "'" + " with index " + i + " is not enabled"
+                    + afterKeyCodeFormattedString + " for" + summary, currentView.isEnabled());
+            assertTrue("View='" + currentView + "'" + " with index " + i + " is not focused"
+                    + afterKeyCodeFormattedString + " for" + summary, currentView.isFocused());
 
-        public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
-            mNotifiedView = view;
-            mNotifiedHourOfDay = hourOfDay;
-            mNotifiedMinute = minute;
-            mHasCalledOnTimeChanged = true;
+            if (i < viewsSize - 1) {
+                if (goForward) {
+                    CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, currentView, goForwardKeyCode);
+                } else {
+                    CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, currentView,
+                            goForwardKeyCode, modifierKeyCodeToHold);
+                }
+            }
         }
     }
 
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index 854247e..696b8a5 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -16,9 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.cts.util.PollingCheck;
@@ -32,6 +29,7 @@
 import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.Toast;
+import android.widget.cts.R;
 
 public class ToastTest extends ActivityInstrumentationTestCase2<CtsActivity> {
     private static final String TEST_TOAST_TEXT = "test toast";
@@ -74,22 +72,12 @@
     }
 
     private void assertShowToast(final View view) {
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return null != view.getParent();
-            }
-        }.run();
+        PollingCheck.waitFor(TIME_OUT, () -> null != view.getParent());
     }
 
     private void assertShowAndHide(final View view) {
         assertShowToast(view);
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return null == view.getParent();
-            }
-        }.run();
+        PollingCheck.waitFor(TIME_OUT, () -> null == view.getParent());
     }
 
     private void assertNotShowToast(final View view) throws InterruptedException {
@@ -104,12 +92,7 @@
     }
 
     private void assertLayoutDone(final View view) {
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mLayoutDone;
-            }
-        }.run();
+        PollingCheck.waitFor(TIME_OUT, () -> mLayoutDone);
         view.getViewTreeObserver().removeOnGlobalLayoutListener(mLayoutListener);
     }
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/tests/tests/widget/src/android/widget/cts/ToggleButtonCtsActivity.java
similarity index 67%
copy from hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
copy to tests/tests/widget/src/android/widget/cts/ToggleButtonCtsActivity.java
index 481f5be..3640957 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ToggleButtonCtsActivity.java
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
-package android.server.app;
+package android.widget.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.ToggleButton;
 
-public class SlowCreateActivity extends Activity {
+/**
+ * A minimal application for {@link ToggleButton} test.
+ */
+public class ToggleButtonCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.togglebutton_layout);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java b/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java
index d335c13..85681e2 100644
--- a/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java
@@ -16,45 +16,49 @@
 
 package android.widget.cts;
 
-import org.xmlpull.v1.XmlPullParser;
-
+import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.util.AttributeSet;
-import android.util.Xml;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.ToggleButton;
-
 import android.widget.cts.R;
 
 
 /**
  * Test {@link ToggleButton}.
  */
-public class ToggleButtonTest extends InstrumentationTestCase {
+@SmallTest
+public class ToggleButtonTest extends ActivityInstrumentationTestCase2<ToggleButtonCtsActivity> {
     private static final String TEXT_OFF = "text off";
     private static final String TEXT_ON = "text on";
-    ToggleButton mToggleButton;
-    Context mContext;
-    AttributeSet mAttrSet;
+
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    public ToggleButtonTest() {
+        super("android.widget.cts", ToggleButtonCtsActivity.class);
+    }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
 
-        mContext = getInstrumentation().getTargetContext();
-        XmlPullParser parser = mContext.getResources().getXml(R.layout.togglebutton_layout);
-        mAttrSet = Xml.asAttributeSet(parser);
-        mToggleButton = new ToggleButton(mContext, mAttrSet);
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
     }
 
     public void testConstructor() {
-        new ToggleButton(mContext, mAttrSet, 0);
-        new ToggleButton(mContext, mAttrSet);
-        new ToggleButton(mContext);
+        new ToggleButton(mActivity);
+        new ToggleButton(mActivity, null);
+        new ToggleButton(mActivity, null, android.R.attr.buttonStyleToggle);
+        new ToggleButton(mActivity, null, 0, android.R.style.Widget_DeviceDefault_Button_Toggle);
+        new ToggleButton(mActivity, null, 0,
+                android.R.style.Widget_DeviceDefault_Light_Button_Toggle);
+        new ToggleButton(mActivity, null, 0, android.R.style.Widget_Material_Button_Toggle);
+        new ToggleButton(mActivity, null, 0, android.R.style.Widget_Material_Light_Button_Toggle);
 
         try {
             new ToggleButton(null, null, -1);
@@ -78,105 +82,127 @@
         }
     }
 
-    public void testAccessTextOff() {
-        mToggleButton.setTextOff("android");
-        assertEquals("android", mToggleButton.getTextOff());
-        mToggleButton.setChecked(false);
-
-        mToggleButton.setTextOff(null);
-        assertNull(mToggleButton.getTextOff());
-
-        mToggleButton.setTextOff("");
-        assertEquals("", mToggleButton.getTextOff());
+    public void testAttributesFromStyle() {
+        final ToggleButton toggleButton =
+                (ToggleButton) mActivity.findViewById(R.id.toggle_with_style);
+        assertEquals(mActivity.getString(R.string.toggle_text_on), toggleButton.getTextOn());
+        assertEquals(mActivity.getString(R.string.toggle_text_off), toggleButton.getTextOff());
     }
 
-    @UiThreadTest
+    public void testAttributesFromLayout() {
+        final ToggleButton toggleButton =
+                (ToggleButton) mActivity.findViewById(R.id.toggle_with_defaults);
+        assertEquals(mActivity.getString(R.string.toggle_text_on_alt), toggleButton.getTextOn());
+        assertEquals(mActivity.getString(R.string.toggle_text_off_alt), toggleButton.getTextOff());
+    }
+
+    public void testAccessTextOff() {
+        final ToggleButton toggleButton = (ToggleButton) mActivity.findViewById(R.id.toggle1);
+        mInstrumentation.runOnMainSync(() -> toggleButton.setTextOff("android"));
+        assertEquals("android", toggleButton.getTextOff());
+        mInstrumentation.runOnMainSync(() -> toggleButton.setChecked(false));
+
+        mInstrumentation.runOnMainSync(() -> toggleButton.setTextOff(null));
+        assertNull(toggleButton.getTextOff());
+
+        mInstrumentation.runOnMainSync(() -> toggleButton.setTextOff(""));
+        assertEquals("", toggleButton.getTextOff());
+    }
+
     public void testDrawableStateChanged() {
-        MockToggleButton toggleButton = new MockToggleButton(mContext);
+        final MockToggleButton toggleButton = new MockToggleButton(mActivity);
 
         // drawableStateChanged without any drawable.
-        toggleButton.drawableStateChanged();
+        mInstrumentation.runOnMainSync(() -> toggleButton.drawableStateChanged());
 
-        StateListDrawable drawable = new StateListDrawable();
+        final StateListDrawable drawable = new StateListDrawable();
         drawable.addState(new int[] { android.R.attr.state_pressed },
-                mContext.getDrawable(R.drawable.scenery));
+                mActivity.getDrawable(R.drawable.scenery));
         drawable.addState(new int[] {},
-                mContext.getDrawable(R.drawable.scenery));
+                mActivity.getDrawable(R.drawable.scenery));
 
         // drawableStateChanged when CheckMarkDrawable is not null.
-        toggleButton.setButtonDrawable(drawable);
+        mInstrumentation.runOnMainSync(() -> toggleButton.setButtonDrawable(drawable));
         drawable.setState(null);
         assertNull(drawable.getState());
 
-        toggleButton.drawableStateChanged();
+        mInstrumentation.runOnMainSync(toggleButton::drawableStateChanged);
         assertNotNull(drawable.getState());
         assertEquals(toggleButton.getDrawableState(), drawable.getState());
     }
 
     public void testOnFinishInflate() {
-        MockToggleButton toggleButton = new MockToggleButton(mContext);
+        MockToggleButton toggleButton = new MockToggleButton(mActivity);
         toggleButton.onFinishInflate();
     }
 
-    @UiThreadTest
     public void testSetChecked() {
-        assertFalse(mToggleButton.isChecked());
+        final ToggleButton toggleButton = (ToggleButton) mActivity.findViewById(R.id.toggle1);
+        assertFalse(toggleButton.isChecked());
 
-        mToggleButton.setChecked(true);
-        assertTrue(mToggleButton.isChecked());
+        mInstrumentation.runOnMainSync(() -> toggleButton.setChecked(true));
+        assertTrue(toggleButton.isChecked());
 
-        mToggleButton.setChecked(false);
-        assertFalse(mToggleButton.isChecked());
+        mInstrumentation.runOnMainSync(() -> toggleButton.setChecked(false));
+        assertFalse(toggleButton.isChecked());
     }
 
-    @UiThreadTest
     public void testToggleText() {
-        mToggleButton.setText("default text");
-        mToggleButton.setTextOn(TEXT_ON);
-        mToggleButton.setTextOff(TEXT_OFF);
-        mToggleButton.setChecked(true);
-        assertEquals(TEXT_ON, mToggleButton.getText().toString());
-        mToggleButton.setChecked(false);
-        assertFalse(mToggleButton.isChecked());
-        assertEquals(TEXT_OFF, mToggleButton.getText().toString());
+        final ToggleButton toggleButton = (ToggleButton) mActivity.findViewById(R.id.toggle1);
+        mInstrumentation.runOnMainSync(() -> {
+            toggleButton.setText("default text");
+            toggleButton.setTextOn(TEXT_ON);
+            toggleButton.setTextOff(TEXT_OFF);
+            toggleButton.setChecked(true);
+        });
+        assertEquals(TEXT_ON, toggleButton.getText().toString());
+        toggleButton.setChecked(false);
+        assertFalse(toggleButton.isChecked());
+        assertEquals(TEXT_OFF, toggleButton.getText().toString());
 
         // Set the current displaying text as TEXT_OFF.
         // Then set checked button, but textOn is null.
-        mToggleButton.setTextOff(TEXT_OFF);
-        mToggleButton.setChecked(false);
-        mToggleButton.setTextOn(null);
-        mToggleButton.setChecked(true);
-        assertEquals(TEXT_OFF, mToggleButton.getText().toString());
+        mInstrumentation.runOnMainSync(() -> {
+            toggleButton.setTextOff(TEXT_OFF);
+            toggleButton.setChecked(false);
+            toggleButton.setTextOn(null);
+            toggleButton.setChecked(true);
+        });
+        assertEquals(TEXT_OFF, toggleButton.getText().toString());
 
         // Set the current displaying text as TEXT_ON. Then set unchecked button,
         // but textOff is null.
-        mToggleButton.setTextOn(TEXT_ON);
-        mToggleButton.setChecked(true);
-        mToggleButton.setTextOff(null);
-        mToggleButton.setChecked(false);
-        assertEquals(TEXT_ON, mToggleButton.getText().toString());
+        mInstrumentation.runOnMainSync(() -> {
+            toggleButton.setTextOn(TEXT_ON);
+            toggleButton.setChecked(true);
+            toggleButton.setTextOff(null);
+            toggleButton.setChecked(false);
+        });
+        assertEquals(TEXT_ON, toggleButton.getText().toString());
     }
 
     public void testSetBackgroundDrawable() {
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.scenery);
+        final ToggleButton toggleButton = (ToggleButton) mActivity.findViewById(R.id.toggle1);
+        final Drawable drawable = mActivity.getDrawable(R.drawable.scenery);
 
-        mToggleButton.setBackgroundDrawable(drawable);
-        assertSame(drawable, mToggleButton.getBackground());
+        mInstrumentation.runOnMainSync(() -> toggleButton.setBackgroundDrawable(drawable));
+        assertSame(drawable, toggleButton.getBackground());
 
         // remove the background
-        mToggleButton.setBackgroundDrawable(null);
-        assertNull(mToggleButton.getBackground());
+        mInstrumentation.runOnMainSync(() -> toggleButton.setBackgroundDrawable(null));
+        assertNull(toggleButton.getBackground());
     }
 
     public void testAccessTextOn() {
-        mToggleButton.setTextOn("cts");
-        assertEquals("cts", mToggleButton.getTextOn());
+        final ToggleButton toggleButton = (ToggleButton) mActivity.findViewById(R.id.toggle1);
+        mInstrumentation.runOnMainSync(() -> toggleButton.setTextOn("cts"));
+        assertEquals("cts", toggleButton.getTextOn());
 
-        mToggleButton.setTextOn(null);
-        assertNull(mToggleButton.getTextOn());
+        mInstrumentation.runOnMainSync(() -> toggleButton.setTextOn(null));
+        assertNull(toggleButton.getTextOn());
 
-        mToggleButton.setTextOn("");
-        assertEquals("", mToggleButton.getTextOn());
+        mInstrumentation.runOnMainSync(() -> toggleButton.setTextOn(""));
+        assertEquals("", toggleButton.getTextOn());
     }
 
     /**
diff --git a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
index 7f9690c..49b879a 100644
--- a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
@@ -16,9 +16,10 @@
 
 package android.widget.cts;
 
+import static org.mockito.Mockito.*;
+
 import android.app.Instrumentation;
-import android.content.Context;
-import android.content.res.TypedArray;
+import android.cts.util.WidgetTestUtils;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.test.ActivityInstrumentationTestCase2;
@@ -27,17 +28,14 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
-import android.widget.ListPopupWindow;
 import android.widget.Toolbar;
 import android.widget.cts.util.TestUtils;
-import android.widget.cts.util.ViewTestUtils;
-
-import static org.mockito.Mockito.*;
 
 @MediumTest
 public class ToolbarTest extends ActivityInstrumentationTestCase2<ToolbarCtsActivity> {
-    private Toolbar mMainToolbar;
+    private Instrumentation mInstrumentation;
     private ToolbarCtsActivity mActivity;
+    private Toolbar mMainToolbar;
 
     public ToolbarTest() {
         super("android.widget.cts", ToolbarCtsActivity.class);
@@ -46,6 +44,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        mInstrumentation = getInstrumentation();
         mActivity = getActivity();
         mMainToolbar = mActivity.getMainToolbar();
     }
@@ -67,45 +67,41 @@
         // of getTitle / getSubtitle, this logic follows the path of deferred layout
         // and invalidation of the TextViews that show the title / subtitle in the Toolbar.
 
-        final Instrumentation instrumentation = getInstrumentation();
-
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setTitle(R.string.toolbar_title));
         assertEquals(mActivity.getString(R.string.toolbar_title), mMainToolbar.getTitle());
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setTitle("New title"));
         assertEquals("New title", mMainToolbar.getTitle());
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setSubtitle(R.string.toolbar_subtitle));
         assertEquals(mActivity.getString(R.string.toolbar_subtitle), mMainToolbar.getSubtitle());
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setSubtitle("New subtitle"));
         assertEquals("New subtitle", mMainToolbar.getSubtitle());
     }
 
     public void testTitleAndSubtitleAppearance() {
-        final Instrumentation instrumentation = getInstrumentation();
-
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setTitle(R.string.toolbar_title));
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setSubtitle(R.string.toolbar_subtitle));
 
         // Since there are no APIs to get reference to the underlying implementation of
         // title and subtitle, here we are testing that calling the relevant APIs doesn't crash
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setTitleTextColor(Color.RED));
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setSubtitleTextColor(Color.BLUE));
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setTitleTextAppearance(
                         mActivity, R.style.TextAppearance_NotColors));
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setSubtitleTextAppearance(
                         mActivity, R.style.TextAppearance_WithColor));
     }
@@ -139,9 +135,7 @@
     }
 
     public void testMenuContent() {
-        final Instrumentation instrumentation = getInstrumentation();
-
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
 
         final Menu menu = mMainToolbar.getMenu();
@@ -170,34 +164,30 @@
     }
 
     public void testMenuOverflowShowHide() {
-        final Instrumentation instrumentation = getInstrumentation();
-
         // Inflate menu and check that we're not showing overflow menu yet
-        instrumentation.runOnMainSync(() -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
         assertFalse(mMainToolbar.isOverflowMenuShowing());
 
         // Ask to show overflow menu and check that it's showing
-        instrumentation.runOnMainSync(() -> mMainToolbar.showOverflowMenu());
-        instrumentation.waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.showOverflowMenu());
+        mInstrumentation.waitForIdleSync();
         assertTrue(mMainToolbar.isOverflowMenuShowing());
 
         // Ask to hide the overflow menu and check that it's not showing
-        instrumentation.runOnMainSync(() -> mMainToolbar.hideOverflowMenu());
-        instrumentation.waitForIdleSync();
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.hideOverflowMenu());
+        mInstrumentation.waitForIdleSync();
         assertFalse(mMainToolbar.isOverflowMenuShowing());
     }
 
     public void testMenuOverflowSubmenu() {
-        final Instrumentation instrumentation = getInstrumentation();
-
         // Inflate menu and check that we're not showing overflow menu yet
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
         assertFalse(mMainToolbar.isOverflowMenuShowing());
 
         // Ask to show overflow menu and check that it's showing
-        instrumentation.runOnMainSync(() -> mMainToolbar.showOverflowMenu());
-        instrumentation.waitForIdleSync();
+        mInstrumentation.runOnMainSync(mMainToolbar::showOverflowMenu);
+        mInstrumentation.waitForIdleSync();
         assertTrue(mMainToolbar.isOverflowMenuShowing());
 
         // Register a mock menu item click listener on the toolbar
@@ -209,162 +199,256 @@
 
         // Ask to "perform" the share action and check that the menu click listener has
         // been notified
-        instrumentation.runOnMainSync(() -> menu.performIdentifierAction(R.id.action_share, 0));
+        mInstrumentation.runOnMainSync(() -> menu.performIdentifierAction(R.id.action_share, 0));
         verify(menuItemClickListener, times(1)).onMenuItemClick(
                 menu.findItem(R.id.action_share));
 
         // Ask to dismiss all the popups and check that we're not showing the overflow menu
-        instrumentation.runOnMainSync(() -> mMainToolbar.dismissPopupMenus());
-        instrumentation.waitForIdleSync();
+        mInstrumentation.runOnMainSync(mMainToolbar::dismissPopupMenus);
+        mInstrumentation.waitForIdleSync();
         assertFalse(mMainToolbar.isOverflowMenuShowing());
     }
 
     public void testMenuOverflowIcon() {
-        final Instrumentation instrumentation = getInstrumentation();
-
         // Inflate menu and check that we're not showing overflow menu yet
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
 
         final Drawable overflowIcon = mActivity.getDrawable(R.drawable.icon_red);
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setOverflowIcon(overflowIcon));
 
         final Drawable toolbarOverflowIcon = mMainToolbar.getOverflowIcon();
         TestUtils.assertAllPixelsOfColor("Overflow icon is red", toolbarOverflowIcon,
                 toolbarOverflowIcon.getIntrinsicWidth(), toolbarOverflowIcon.getIntrinsicHeight(),
-                true, 0XFFFF0000, 1, false);
+                true, Color.RED, 1, false);
     }
 
     public void testActionView() {
-        final Instrumentation instrumentation = getInstrumentation();
-
         // Inflate menu and check that we don't have an expanded action view
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu_search));
         assertFalse(mMainToolbar.hasExpandedActionView());
 
         // Expand search menu item's action view and verify that main toolbar has an expanded
         // action view
         final MenuItem searchMenuItem = mMainToolbar.getMenu().findItem(R.id.action_search);
-        instrumentation.runOnMainSync(() -> searchMenuItem.expandActionView());
-        instrumentation.waitForIdleSync();
+        mInstrumentation.runOnMainSync(searchMenuItem::expandActionView);
+        mInstrumentation.waitForIdleSync();
         assertTrue(searchMenuItem.isActionViewExpanded());
         assertTrue(mMainToolbar.hasExpandedActionView());
 
         // Collapse search menu item's action view and verify that main toolbar doesn't have an
         // expanded action view
-        instrumentation.runOnMainSync(() -> searchMenuItem.collapseActionView());
-        instrumentation.waitForIdleSync();
+        mInstrumentation.runOnMainSync(searchMenuItem::collapseActionView);
+        mInstrumentation.waitForIdleSync();
         assertFalse(searchMenuItem.isActionViewExpanded());
         assertFalse(mMainToolbar.hasExpandedActionView());
 
         // Expand search menu item's action view again
-        instrumentation.runOnMainSync(() -> searchMenuItem.expandActionView());
-        instrumentation.waitForIdleSync();
+        mInstrumentation.runOnMainSync(searchMenuItem::expandActionView);
+        mInstrumentation.waitForIdleSync();
         assertTrue(searchMenuItem.isActionViewExpanded());
         assertTrue(mMainToolbar.hasExpandedActionView());
 
         // Now collapse search menu item's action view via toolbar's API and verify that main
         // toolbar doesn't have an expanded action view
-        instrumentation.runOnMainSync(() -> mMainToolbar.collapseActionView());
-        instrumentation.waitForIdleSync();
+        mInstrumentation.runOnMainSync(mMainToolbar::collapseActionView);
+        mInstrumentation.waitForIdleSync();
         assertFalse(searchMenuItem.isActionViewExpanded());
         assertFalse(mMainToolbar.hasExpandedActionView());
     }
 
     public void testNavigationConfiguration() {
-        final Instrumentation instrumentation = getInstrumentation();
-
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setNavigationIcon(R.drawable.icon_green));
         Drawable toolbarNavigationIcon = mMainToolbar.getNavigationIcon();
         TestUtils.assertAllPixelsOfColor("Navigation icon is green", toolbarNavigationIcon,
                 toolbarNavigationIcon.getIntrinsicWidth(),
                 toolbarNavigationIcon.getIntrinsicHeight(),
-                true, 0xFF00FF00, 1, false);
+                true, Color.GREEN, 1, false);
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setNavigationIcon(mActivity.getDrawable(R.drawable.icon_blue)));
         toolbarNavigationIcon = mMainToolbar.getNavigationIcon();
         TestUtils.assertAllPixelsOfColor("Navigation icon is blue", toolbarNavigationIcon,
                 toolbarNavigationIcon.getIntrinsicWidth(),
                 toolbarNavigationIcon.getIntrinsicHeight(),
-                true, 0xFF0000FF, 1, false);
+                true, Color.BLUE, 1, false);
 
-        instrumentation.runOnMainSync(
+        mInstrumentation.runOnMainSync(
                 () -> mMainToolbar.setNavigationContentDescription(R.string.toolbar_navigation));
         assertEquals(mActivity.getResources().getString(R.string.toolbar_navigation),
                 mMainToolbar.getNavigationContentDescription());
 
-        instrumentation.runOnMainSync(
+        mInstrumentation.runOnMainSync(
                 () -> mMainToolbar.setNavigationContentDescription("Navigation legend"));
         assertEquals("Navigation legend", mMainToolbar.getNavigationContentDescription());
     }
 
     public void testLogoConfiguration() {
-        final Instrumentation instrumentation = getInstrumentation();
-
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setLogo(R.drawable.icon_yellow));
         Drawable toolbarLogo = mMainToolbar.getLogo();
         TestUtils.assertAllPixelsOfColor("Logo is yellow", toolbarLogo,
                 toolbarLogo.getIntrinsicWidth(),
                 toolbarLogo.getIntrinsicHeight(),
-                true, 0xFFFFFF00, 1, false);
+                true, Color.YELLOW, 1, false);
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
                 () -> mMainToolbar.setLogo(mActivity.getDrawable(R.drawable.icon_red)));
         toolbarLogo = mMainToolbar.getLogo();
         TestUtils.assertAllPixelsOfColor("Logo is red", toolbarLogo,
                 toolbarLogo.getIntrinsicWidth(),
                 toolbarLogo.getIntrinsicHeight(),
-                true, 0xFFFF0000, 1, false);
+                true, Color.RED, 1, false);
 
-        instrumentation.runOnMainSync(
+        mInstrumentation.runOnMainSync(
                 () -> mMainToolbar.setLogoDescription(R.string.toolbar_logo));
         assertEquals(mActivity.getResources().getString(R.string.toolbar_logo),
                 mMainToolbar.getLogoDescription());
 
-        instrumentation.runOnMainSync(
+        mInstrumentation.runOnMainSync(
                 () -> mMainToolbar.setLogoDescription("Logo legend"));
         assertEquals("Logo legend", mMainToolbar.getLogoDescription());
     }
 
-    @UiThreadTest
     public void testContentInsetsLtr() {
-        mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+        mInstrumentation.runOnMainSync(
+                () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
 
-        mMainToolbar.setContentInsetsAbsolute(20, 25);
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsAbsolute(20, 25));
         assertEquals(20, mMainToolbar.getContentInsetLeft());
         assertEquals(20, mMainToolbar.getContentInsetStart());
         assertEquals(25, mMainToolbar.getContentInsetRight());
         assertEquals(25, mMainToolbar.getContentInsetEnd());
 
-        mMainToolbar.setContentInsetsRelative(40, 20);
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsRelative(40, 20));
         assertEquals(40, mMainToolbar.getContentInsetLeft());
         assertEquals(40, mMainToolbar.getContentInsetStart());
         assertEquals(20, mMainToolbar.getContentInsetRight());
         assertEquals(20, mMainToolbar.getContentInsetEnd());
     }
 
-    @UiThreadTest
     public void testContentInsetsRtl() {
-        mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+        mInstrumentation.runOnMainSync(
+                () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_RTL));
 
-        mMainToolbar.setContentInsetsAbsolute(20, 25);
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsAbsolute(20, 25));
         assertEquals(20, mMainToolbar.getContentInsetLeft());
         assertEquals(25, mMainToolbar.getContentInsetStart());
         assertEquals(25, mMainToolbar.getContentInsetRight());
         assertEquals(20, mMainToolbar.getContentInsetEnd());
 
-        mMainToolbar.setContentInsetsRelative(40, 20);
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsRelative(40, 20));
         assertEquals(20, mMainToolbar.getContentInsetLeft());
         assertEquals(40, mMainToolbar.getContentInsetStart());
         assertEquals(40, mMainToolbar.getContentInsetRight());
         assertEquals(20, mMainToolbar.getContentInsetEnd());
     }
 
+    public void testCurrentContentInsetsLtr() {
+        mInstrumentation.runOnMainSync(
+                () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsRelative(20, 25));
+        assertEquals(20, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetStartWithNavigation(50));
+        assertEquals(50, mMainToolbar.getContentInsetStartWithNavigation());
+        // Since we haven't configured the navigation icon itself, the current content insets
+        // should stay the same
+        assertEquals(20, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
+                () -> mMainToolbar.setNavigationIcon(R.drawable.icon_green));
+        assertEquals(50, mMainToolbar.getContentInsetStartWithNavigation());
+        // Since we have configured the navigation icon, and the currently set start inset with
+        // navigation is bigger than currently set start content inset, we should be getting that
+        // bigger value now
+        assertEquals(50, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetEndWithActions(35));
+        assertEquals(35, mMainToolbar.getContentInsetEndWithActions());
+        // Since we haven't configured the menu content, the current content insets
+        // should stay the same
+        assertEquals(50, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
+                () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
+        assertEquals(35, mMainToolbar.getContentInsetEndWithActions());
+        // Since we have configured the menu content, and the currently set start inset with
+        // navigation is bigger than currently set end content inset, we should be getting that
+        // bigger value now
+        assertEquals(50, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(35, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(35, mMainToolbar.getCurrentContentInsetEnd());
+    }
+
+    public void testCurrentContentInsetsRtl() {
+        mInstrumentation.runOnMainSync(
+                () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_RTL));
+
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsRelative(20, 25));
+        assertEquals(25, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(20, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetStartWithNavigation(50));
+        assertEquals(50, mMainToolbar.getContentInsetStartWithNavigation());
+        // Since we haven't configured the navigation icon itself, the current content insets
+        // should stay the same
+        assertEquals(25, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(20, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
+                () -> mMainToolbar.setNavigationIcon(R.drawable.icon_green));
+        assertEquals(50, mMainToolbar.getContentInsetStartWithNavigation());
+        // Since we have configured the navigation icon, and the currently set start inset with
+        // navigation is bigger than currently set start content inset, we should be getting that
+        // bigger value now
+        assertEquals(25, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(50, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetEndWithActions(35));
+        assertEquals(35, mMainToolbar.getContentInsetEndWithActions());
+        // Since we haven't configured the menu content, the current content insets
+        // should stay the same
+        assertEquals(25, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(50, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        WidgetTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
+                () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
+        assertEquals(35, mMainToolbar.getContentInsetEndWithActions());
+        // Since we have configured the menu content, and the currently set start inset with
+        // navigation is bigger than currently set end content inset, we should be getting that
+        // bigger value now
+        assertEquals(35, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(50, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(35, mMainToolbar.getCurrentContentInsetEnd());
+    }
+
     @UiThreadTest
     public void testPopupTheme() {
         mMainToolbar.setPopupTheme(R.style.ToolbarPopupTheme_Test);
@@ -377,7 +461,7 @@
 
         verify(mockListener, never()).onClick(any(View.class));
 
-        getInstrumentation().runOnMainSync(() -> mMainToolbar.getNavigationView().performClick());
+        mInstrumentation.runOnMainSync(() -> mMainToolbar.getNavigationView().performClick());
         verify(mockListener, times(1)).onClick(any(View.class));
 
         verifyNoMoreInteractions(mockListener);
diff --git a/tests/tests/widget/src/android/widget/cts/TwoLineListItemCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TwoLineListItemCtsActivity.java
index 68413ff..fe8b637 100644
--- a/tests/tests/widget/src/android/widget/cts/TwoLineListItemCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/TwoLineListItemCtsActivity.java
@@ -16,11 +16,10 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.TwoLineListItem;
+import android.widget.cts.R;
 
 /**
  * Stub activity for testing {@link TwoLineListItem}
diff --git a/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java b/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java
index 4ee22a1..d0c00f8 100644
--- a/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java
@@ -16,17 +16,15 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Resources;
 import android.test.ActivityInstrumentationTestCase;
 import android.util.AttributeSet;
+import android.widget.RelativeLayout.LayoutParams;
 import android.widget.TextView;
 import android.widget.TwoLineListItem;
-import android.widget.RelativeLayout.LayoutParams;
+import android.widget.cts.R;
 
 /**
  * Test {@link TwoLineListItem}.
diff --git a/tests/tests/widget/src/android/widget/cts/VideoViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/VideoViewCtsActivity.java
index e831f04..903c5c2 100644
--- a/tests/tests/widget/src/android/widget/cts/VideoViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/VideoViewCtsActivity.java
@@ -16,11 +16,10 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.VideoView;
+import android.widget.cts.R;
 
 /**
  * A minimal application for {@link VideoView} test.
diff --git a/tests/tests/widget/src/android/widget/cts/VideoViewTest.java b/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
index 265b802..8ceabf1 100644
--- a/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
@@ -16,19 +16,14 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.cts.util.MediaUtils;
-import android.cts.util.PollingCheck;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecList;
 import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.media.MediaPlayer.OnErrorListener;
-import android.media.MediaPlayer.OnPreparedListener;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.util.Log;
@@ -36,9 +31,13 @@
 import android.widget.MediaController;
 import android.widget.VideoView;
 
+import org.mockito.invocation.InvocationOnMock;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test {@link VideoView}.
@@ -63,43 +62,6 @@
     private Instrumentation mInstrumentation;
     private String mVideoPath;
 
-    private static class MockListener {
-        private boolean mTriggered;
-
-        MockListener() {
-            mTriggered = false;
-        }
-
-        public boolean isTriggered() {
-            return mTriggered;
-        }
-
-        protected void onEvent() {
-            mTriggered = true;
-        }
-    }
-
-    private static class MockOnPreparedListener extends MockListener
-            implements OnPreparedListener {
-        public void onPrepared(MediaPlayer mp) {
-            super.onEvent();
-        }
-    }
-
-    private static class MockOnErrorListener extends MockListener implements OnErrorListener {
-        public boolean onError(MediaPlayer mp, int what, int extra) {
-            super.onEvent();
-            return false;
-        }
-    }
-
-    private static class MockOnCompletionListener extends MockListener
-            implements OnCompletionListener {
-        public void onCompletion(MediaPlayer mp) {
-            super.onEvent();
-        }
-    }
-
     private boolean hasCodec() {
         return MediaUtils.hasCodecsForResource(mActivity, R.raw.testvideo);
     }
@@ -190,42 +152,46 @@
             return;
         }
 
-        final MockOnPreparedListener preparedListener = new MockOnPreparedListener();
-        mVideoView.setOnPreparedListener(preparedListener);
-        final MockOnCompletionListener completionListener = new MockOnCompletionListener();
-        mVideoView.setOnCompletionListener(completionListener);
+        final MediaPlayer.OnPreparedListener mockPreparedListener =
+                mock(MediaPlayer.OnPreparedListener.class);
+        final CountDownLatch preparedLatch = new CountDownLatch(1);
+        doAnswer((InvocationOnMock invocation) -> {
+            preparedLatch.countDown();
+            return null;
+        }).when(mockPreparedListener).onPrepared(any(MediaPlayer.class));
+        mVideoView.setOnPreparedListener(mockPreparedListener);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mVideoView.setVideoPath(mVideoPath);
-            }
-        });
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return preparedListener.isTriggered();
-            }
-        }.run();
-        assertFalse(completionListener.isTriggered());
+        final MediaPlayer.OnCompletionListener mockCompletionListener =
+                mock(MediaPlayer.OnCompletionListener.class);
+        final CountDownLatch completionLatch = new CountDownLatch(1);
+        doAnswer((InvocationOnMock invocation) -> {
+            completionLatch.countDown();
+            return null;
+        }).when(mockCompletionListener).onCompletion(any(MediaPlayer.class));
+        mVideoView.setOnCompletionListener(mockCompletionListener);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mVideoView.start();
-            }
-        });
+        runTestOnUiThread(() -> mVideoView.setVideoPath(mVideoPath));
+        preparedLatch.await(TIME_OUT, TimeUnit.MILLISECONDS);
+        verify(mockPreparedListener, times(1)).onPrepared(any(MediaPlayer.class));
+        verifyZeroInteractions(mockCompletionListener);
+
+        runTestOnUiThread(mVideoView::start);
         // wait time is longer than duration in case system is sluggish
-        new PollingCheck(mVideoView.getDuration() + TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return completionListener.isTriggered();
-            }
-        }.run();
+        completionLatch.await(mVideoView.getDuration() + TIME_OUT, TimeUnit.MILLISECONDS);
+        verify(mockCompletionListener, times(1)).onCompletion(any(MediaPlayer.class));
     }
 
     public void testSetOnErrorListener() throws Throwable {
         makeVideoView();
-        final MockOnErrorListener listener = new MockOnErrorListener();
-        mVideoView.setOnErrorListener(listener);
+
+        final MediaPlayer.OnErrorListener mockErrorListener =
+                mock(MediaPlayer.OnErrorListener.class);
+        final CountDownLatch errorLatch = new CountDownLatch(1);
+        doAnswer((InvocationOnMock invocation) -> {
+            errorLatch.countDown();
+            return null;
+        }).when(mockErrorListener).onError(any(MediaPlayer.class), anyInt(), anyInt());
+        mVideoView.setOnErrorListener(mockErrorListener);
 
         runTestOnUiThread(new Runnable() {
             public void run() {
@@ -236,12 +202,8 @@
         });
         mInstrumentation.waitForIdleSync();
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return listener.isTriggered();
-            }
-        }.run();
+        errorLatch.await(TIME_OUT, TimeUnit.MILLISECONDS);
+        verify(mockErrorListener, times(1)).onError(any(MediaPlayer.class), anyInt(), anyInt());
     }
 
     public void testGetBufferPercentage() throws Throwable {
@@ -252,22 +214,20 @@
             return;
         }
 
-        final MockOnPreparedListener prepareListener = new MockOnPreparedListener();
-        mVideoView.setOnPreparedListener(prepareListener);
+        final MediaPlayer.OnPreparedListener mockPreparedListener =
+                mock(MediaPlayer.OnPreparedListener.class);
+        final CountDownLatch preparedLatch = new CountDownLatch(1);
+        doAnswer((InvocationOnMock invocation) -> {
+            preparedLatch.countDown();
+            return null;
+        }).when(mockPreparedListener).onPrepared(any(MediaPlayer.class));
+        mVideoView.setOnPreparedListener(mockPreparedListener);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mVideoView.setVideoPath(mVideoPath);
-            }
-        });
+        runTestOnUiThread(() -> mVideoView.setVideoPath(mVideoPath));
         mInstrumentation.waitForIdleSync();
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return prepareListener.isTriggered();
-            }
-        }.run();
+        preparedLatch.await(TIME_OUT, TimeUnit.MILLISECONDS);
+        verify(mockPreparedListener, times(1)).onPrepared(any(MediaPlayer.class));
         int percent = mVideoView.getBufferPercentage();
         assertTrue(percent >= 0 && percent <= 100);
     }
@@ -295,11 +255,7 @@
             return;
         }
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mVideoView.setVideoPath(mVideoPath);
-            }
-        });
+        runTestOnUiThread(() -> mVideoView.setVideoPath(mVideoPath));
         waitForOperationComplete();
         assertTrue(Math.abs(mVideoView.getDuration() - TEST_VIDEO_DURATION) < DURATION_DELTA);
     }
diff --git a/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java b/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java
index 696761b..7e93fe3 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java
@@ -16,11 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
@@ -34,6 +29,9 @@
 import android.view.animation.AnimationSet;
 import android.widget.RelativeLayout;
 import android.widget.ViewAnimator;
+import android.widget.cts.R;
+
+import org.xmlpull.v1.XmlPullParser;
 
 public class ViewAnimatorTest extends
         ActivityInstrumentationTestCase2<ViewAnimatorCtsActivity> {
diff --git a/tests/tests/widget/src/android/widget/cts/ViewFlipperCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ViewFlipperCtsActivity.java
index ba90590..f3a37a6 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewFlipperCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewFlipperCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 public class ViewFlipperCtsActivity extends Activity {
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java b/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java
index 5ec242e..a01f79f 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java
@@ -16,11 +16,6 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
 import android.test.UiThreadTest;
@@ -29,6 +24,9 @@
 import android.view.View;
 import android.widget.TextView;
 import android.widget.ViewFlipper;
+import android.widget.cts.R;
+
+import org.xmlpull.v1.XmlPullParser;
 
 /**
  * Test {@link ViewFlipper}.
diff --git a/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java b/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java
index 7828570..3b824b5 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java
@@ -16,9 +16,6 @@
 
 package android.widget.cts;
 
-import org.xmlpull.v1.XmlPullParser;
-
-import android.content.Context;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.Xml;
@@ -27,9 +24,10 @@
 import android.widget.ListView;
 import android.widget.ViewSwitcher;
 import android.widget.ViewSwitcher.ViewFactory;
-
 import android.widget.cts.R;
 
+import org.xmlpull.v1.XmlPullParser;
+
 
 /**
  * Test {@link ViewSwitcher}.
diff --git a/tests/tests/widget/src/android/widget/cts/ZoomButtonCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ZoomButtonCtsActivity.java
index 28563f5..1a50217 100644
--- a/tests/tests/widget/src/android/widget/cts/ZoomButtonCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/ZoomButtonCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.cts.R;
 
 /**
  * A minimal application for {@link ZoomButton} test.
diff --git a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
index 493c484..7192386 100644
--- a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
@@ -16,23 +16,28 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.app.Activity;
-import android.cts.util.PollingCheck;
+import android.cts.util.CtsTouchUtils;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
-import android.view.View.OnClickListener;
+import android.view.ViewConfiguration;
 import android.widget.ListView;
 import android.widget.ZoomButton;
 
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@SmallTest
 public class ZoomButtonTest extends ActivityInstrumentationTestCase2<ZoomButtonCtsActivity> {
+    private static long NANOS_IN_MILLI = 1000000;
     private ZoomButton mZoomButton;
     private Activity mActivity;
 
@@ -54,7 +59,9 @@
 
         new ZoomButton(mActivity, null);
 
-        new ZoomButton(mActivity, null, 0);
+        new ZoomButton(mActivity, null, android.R.attr.imageButtonStyle);
+
+        new ZoomButton(mActivity, null, 0, android.R.style.Widget_Material_Light_ImageButton);
 
         XmlPullParser parser = mActivity.getResources().getXml(R.layout.zoombutton_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -81,6 +88,7 @@
         }
     }
 
+    @UiThreadTest
     public void testSetEnabled() {
         assertFalse(mZoomButton.isPressed());
         mZoomButton.setEnabled(true);
@@ -105,21 +113,54 @@
         assertFalse(mZoomButton.dispatchUnhandledMove(null, View.FOCUS_DOWN));
     }
 
-    public void testOnLongClick() {
-        final MockOnClickListener listener = new MockOnClickListener();
-        mZoomButton.setOnClickListener(listener);
-        mZoomButton.setEnabled(true);
-        long speed = 2000;
-        mZoomButton.setZoomSpeed(speed);
+    private void verifyZoomSpeed(ZoomClickListener zoomClickListener, long zoomSpeedMs) {
+        mZoomButton.setZoomSpeed(zoomSpeedMs);
 
-        assertFalse(listener.hasOnClickCalled());
-        mZoomButton.performLongClick();
-        new PollingCheck(speed + 500) {
-            @Override
-            protected boolean check() {
-                return listener.hasOnClickCalled();
+        final long startTime = System.nanoTime();
+        // Emulate long click that "lasts" for ten seconds
+        CtsTouchUtils.emulateLongClick(getInstrumentation(), mZoomButton, 10000);
+
+        final List<Long> callbackInvocations = zoomClickListener.getClickTimes();
+        assertFalse("Expecting at least one callback", callbackInvocations.isEmpty());
+
+        // Verify that the first callback is fired after the system-level long press timeout.
+        final long minTimeUntilFirstInvocationMs = ViewConfiguration.getLongPressTimeout();
+        final long actualTimeUntilFirstInvocationNs = callbackInvocations.get(0) - startTime;
+        assertTrue("First callback not during long press timeout was " +
+                        actualTimeUntilFirstInvocationNs / NANOS_IN_MILLI +
+                        " while long press timeout is " + minTimeUntilFirstInvocationMs,
+                (callbackInvocations.get(0) - startTime) >
+                        minTimeUntilFirstInvocationMs * NANOS_IN_MILLI);
+
+        // Verify that subsequent callbacks are at least zoom-speed milliseconds apart. Note that
+        // we do not have any hard guarantee about the max limit on the time between successive
+        // callbacks.
+        final long minTimeBetweenInvocationsNs = zoomSpeedMs * NANOS_IN_MILLI;
+        if (callbackInvocations.size() > 1) {
+            for (int i = 0; i < callbackInvocations.size() - 1; i++) {
+                final long actualTimeBetweenInvocationsNs =
+                        (callbackInvocations.get(i + 1) - callbackInvocations.get(i)) *
+                                NANOS_IN_MILLI;
+                assertTrue("Callback " + (i + 1) + " happened " +
+                                actualTimeBetweenInvocationsNs / NANOS_IN_MILLI +
+                                " after the previous one, while zoom speed is " + zoomSpeedMs,
+                        actualTimeBetweenInvocationsNs > minTimeBetweenInvocationsNs);
             }
-        };
+        }
+    }
+
+    @LargeTest
+    public void testOnLongClick() {
+        // Since Mockito doesn't have utilities to track the timestamps of method invocations,
+        // we're using our own custom click listener for that. We want to verify that the
+        // first listener invocation was after long press timeout, and the rest were spaced
+        // by at least our zoom speed milliseconds
+
+        mZoomButton.setEnabled(true);
+        ZoomClickListener zoomClickListener = new ZoomClickListener();
+        mZoomButton.setOnClickListener(zoomClickListener);
+
+        verifyZoomSpeed(zoomClickListener, 2000);
     }
 
     public void testOnTouchEvent() {
@@ -130,22 +171,35 @@
         // Do not test. Implementation details.
     }
 
+    @LargeTest
     public void testSetZoomSpeed() {
-        mZoomButton.setZoomSpeed(100);
+        final long[] zoomSpeeds = { 100, -1, 5000, 1000, 2500 };
+        mZoomButton.setEnabled(true);
+        ZoomClickListener zoomClickListener = new ZoomClickListener();
+        mZoomButton.setOnClickListener(zoomClickListener);
 
-        mZoomButton.setZoomSpeed(-1);
-        // TODO: how to check?
+        for (long zoomSpeed : zoomSpeeds) {
+            // Reset the tracker list of our listener, but continue using it for testing
+            // various zoom speeds on the same ZoomButton
+            zoomClickListener.reset();
+            verifyZoomSpeed(zoomClickListener, zoomSpeed);
+        }
     }
 
-    private static class MockOnClickListener implements OnClickListener {
-        private boolean mOnClickCalled = false;
+    private static class ZoomClickListener implements View.OnClickListener {
+        private List<Long> mClickTimes = new ArrayList<>();
 
-        public boolean hasOnClickCalled() {
-            return mOnClickCalled;
+        public void reset() {
+            mClickTimes.clear();
+        }
+
+        public List<Long> getClickTimes() {
+            return Collections.unmodifiableList(mClickTimes);
         }
 
         public void onClick(View v) {
-            mOnClickCalled = true;
+            // Add the current system time to the tracker list
+            mClickTimes.add(System.nanoTime());
         }
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/appwidget/MyAppWidgetProvider.java b/tests/tests/widget/src/android/widget/cts/appwidget/MyAppWidgetProvider.java
new file mode 100644
index 0000000..fd89cf1
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/appwidget/MyAppWidgetProvider.java
@@ -0,0 +1,177 @@
+/*
+ * 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.widget.cts.appwidget;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.Context;
+import android.content.Intent;
+import android.cts.util.PollingCheck;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+import android.widget.RemoteViews;
+import android.widget.cts.R;
+
+import java.util.concurrent.CountDownLatch;
+
+public final class MyAppWidgetProvider extends AppWidgetProvider {
+    private static final long TIME_SLICE = 100;
+
+    public static final String KEY_DISPLAYED_CHILD_INDEX =
+            "MyAppWidgetProvider.displayedChildIndex";
+    public static final String KEY_SHOW_NEXT = "MyAppWidgetProvider.showNext";
+    public static final String KEY_SHOW_PREVIOUS = "MyAppWidgetProvider.showPrevious";
+    public static final String KEY_SWITCH_TO_LIST = "MyAppWidgetProvider.switchToList";
+    public static final String KEY_SCROLL_POSITION = "MyAppWidgetProvider.scrollPosition";
+    public static final String KEY_SCROLL_OFFSET = "MyAppWidgetProvider.scrollOffset";
+
+    // This latch will be notified when onEnabled is called on our provider.
+    private static CountDownLatch sCountDownLatch;
+    // Gating condition to be polled to proceed with setScrollPosition call.
+    private static PollingCheck.PollingCheckCondition sSetScrollCondition;
+    // Gating condition to be polled to proceed with setRelativeScrollPosition call.
+    private static PollingCheck.PollingCheckCondition sSetRelativeScrollCondition;
+
+    private int mDisplayedChildIndex;
+    private boolean mShowNext;
+    private boolean mShowPrevious;
+    private boolean mSwitchToList;
+    private int mScrollPosition;
+    private int mScrollOffset;
+
+    public static void configure(CountDownLatch countDownLatch,
+            PollingCheck.PollingCheckCondition setScrollCondition,
+            PollingCheck.PollingCheckCondition setRelativeScrollCondition) {
+        sCountDownLatch = countDownLatch;
+        sSetScrollCondition = setScrollCondition;
+        sSetRelativeScrollCondition = setRelativeScrollCondition;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        mDisplayedChildIndex = intent.getIntExtra(KEY_DISPLAYED_CHILD_INDEX, -1);
+        mShowNext = intent.getBooleanExtra(KEY_SHOW_NEXT, false);
+        mShowPrevious = intent.getBooleanExtra(KEY_SHOW_PREVIOUS, false);
+        mSwitchToList = intent.getBooleanExtra(KEY_SWITCH_TO_LIST, false);
+        mScrollPosition = intent.getIntExtra(KEY_SCROLL_POSITION, -1);
+        mScrollOffset = intent.getIntExtra(KEY_SCROLL_OFFSET, 0);
+
+        super.onReceive(context, intent);
+    }
+
+    @Override
+    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+        final int appWidgetId = appWidgetIds[0];
+        final RemoteViews widgetAdapterView = new RemoteViews(context.getPackageName(),
+                R.layout.remoteviews_adapter);
+
+        final Intent stackIntent = new Intent(context, MyAppWidgetService.class);
+        stackIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+        stackIntent.setData(Uri.parse(stackIntent.toUri(Intent.URI_INTENT_SCHEME)));
+
+        widgetAdapterView.setRemoteAdapter(R.id.remoteViews_stack, stackIntent);
+        widgetAdapterView.setEmptyView(R.id.remoteViews_stack, R.id.remoteViews_empty);
+
+        if (mDisplayedChildIndex >= 0) {
+            widgetAdapterView.setDisplayedChild(R.id.remoteViews_stack, mDisplayedChildIndex);
+        }
+        if (mShowNext) {
+            widgetAdapterView.showNext(R.id.remoteViews_stack);
+        }
+        if (mShowPrevious) {
+            widgetAdapterView.showPrevious(R.id.remoteViews_stack);
+        }
+
+        // Here we setup the a pending intent template. Individuals items of a collection
+        // cannot setup their own pending intents, instead, the collection as a whole can
+        // setup a pending intent template, and the individual items can set a fillInIntent
+        // to create unique before on an item to item basis.
+        Intent viewIntent = new Intent(Intent.ACTION_VIEW,
+                Uri.parse("ctstest://RemoteView/testWidget"));
+        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, viewIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+
+        widgetAdapterView.setPendingIntentTemplate(R.id.remoteViews_stack, pendingIntent);
+
+        if (mSwitchToList) {
+            final Intent listIntent = new Intent(context, MyAppWidgetService.class);
+            listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+            listIntent.setData(Uri.parse(stackIntent.toUri(Intent.URI_INTENT_SCHEME)));
+
+            widgetAdapterView.setRemoteAdapter(R.id.remoteViews_list, listIntent);
+
+            widgetAdapterView.setViewVisibility(R.id.remoteViews_stack, View.GONE);
+            widgetAdapterView.setViewVisibility(R.id.remoteViews_list, View.VISIBLE);
+        }
+
+        final Handler handler = new Handler(Looper.myLooper());
+        if (mScrollPosition >= 0) {
+            // We need to schedule the call to setScrollPosition as a separate event that runs
+            // after the underlying ListView has been laid out on the screen. Otherwise calling
+            // that API on a ListView with 0x0 dimension has no effect - the list content is only
+            // populated via the adapter when ListView has "real" bounds.
+            final Runnable setScrollRunnable = new Runnable() {
+                public void run() {
+                    if (sSetScrollCondition.canProceed()) {
+                        // Gating condition has been satisfied. Call setScrollPosition and
+                        // ask the widget manager to update our widget
+                        widgetAdapterView.setScrollPosition(R.id.remoteViews_list, mScrollPosition);
+                        appWidgetManager.partiallyUpdateAppWidget(appWidgetId, widgetAdapterView);
+                    } else {
+                        // Keep on "waiting" until the gating condition is satisfied
+                        handler.postDelayed(this, TIME_SLICE);
+                    }
+                }
+            };
+            handler.postDelayed(setScrollRunnable, TIME_SLICE);
+        }
+
+        if (mScrollOffset != 0) {
+            // We need to schedule the call to setRelativeScrollPosition as a separate event that
+            // runs after the underlying ListView has been laid out on the screen. Otherwise calling
+            // that API on a ListView with 0x0 dimension has no effect - the list content is only
+            // populated via the adapter when ListView has "real" bounds.
+            final Runnable setRelativeScrollRunnable = new Runnable() {
+                public void run() {
+                    if (sSetRelativeScrollCondition.canProceed()) {
+                        // Gating condition has been satisfied. Call setRelativeScrollPosition and
+                        // ask the widget manager to update our widget
+                        widgetAdapterView.setRelativeScrollPosition(
+                                R.id.remoteViews_list, mScrollOffset);
+                        appWidgetManager.partiallyUpdateAppWidget(appWidgetId, widgetAdapterView);
+                    } else {
+                        // Keep on "waiting" until the gating condition is satisfied
+                        handler.postDelayed(this, TIME_SLICE);
+                    }
+                }
+            };
+            handler.postDelayed(setRelativeScrollRunnable, TIME_SLICE);
+        }
+
+        appWidgetManager.updateAppWidget(appWidgetId, widgetAdapterView);
+
+        sCountDownLatch.countDown();
+    }
+
+    @Override
+    public void onEnabled(Context context) {
+        sCountDownLatch.countDown();
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/appwidget/MyAppWidgetService.java b/tests/tests/widget/src/android/widget/cts/appwidget/MyAppWidgetService.java
new file mode 100644
index 0000000..7fc6b49
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/appwidget/MyAppWidgetService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.widget.cts.appwidget;
+
+import android.content.Intent;
+import android.widget.RemoteViewsService;
+
+public class MyAppWidgetService extends RemoteViewsService {
+    private static final Object sLock = new Object();
+
+    private static RemoteViewsFactory sFactory;
+
+    public static void setFactory(RemoteViewsFactory factory) {
+        synchronized (sLock) {
+            sFactory = factory;
+        }
+    }
+
+    @Override
+    public RemoteViewsFactory onGetViewFactory(Intent intent) {
+        synchronized (sLock) {
+            return sFactory;
+        }
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/util/ExpandableListScenario.java b/tests/tests/widget/src/android/widget/cts/util/ExpandableListScenario.java
index 1b2eb15..7e72e88 100644
--- a/tests/tests/widget/src/android/widget/cts/util/ExpandableListScenario.java
+++ b/tests/tests/widget/src/android/widget/cts/util/ExpandableListScenario.java
@@ -54,7 +54,10 @@
 
     @Override
     protected void setAdapter(ListView listView) {
-        ((ExpandableListView) listView).setAdapter(mAdapter = createAdapter());
+        mAdapter = createAdapter();
+        if (mAdapter != null) {
+            ((ExpandableListView) listView).setAdapter(mAdapter);
+        }
     }
 
     protected ExpandableListAdapter createAdapter() {
@@ -91,7 +94,7 @@
         /**
          * Sets the number of children per group.
          *
-         * @param numChildrenPerGroup The number of children per group.
+         * @param numChildren The number of children per group.
          */
         public ExpandableParams setNumChildren(int[] numChildren) {
             mNumChildren = numChildren;
@@ -275,6 +278,10 @@
      * @return A group index with the requirements.
      */
     public int findGroupWithNumChildren(int numChildren, boolean atLeastOneChild) {
+        if (mAdapter == null) {
+            return -1;
+        }
+
         final ExpandableListAdapter adapter = mAdapter;
 
         for (int i = adapter.getGroupCount() - 1; i >= 0; i--) {
@@ -292,10 +299,6 @@
         return mGroups;
     }
 
-    public ExpandableListAdapter getAdapter() {
-        return mAdapter;
-    }
-
     /**
      * Simple expandable list adapter.
      */
@@ -348,10 +351,10 @@
     }
 
     public static class MyGroup {
-        private static long mNextId = 1000;
+        private static long sNextId = 1000;
 
         String name;
-        long id = mNextId++;
+        long id = sNextId++;
         List<MyChild> children;
 
         public MyGroup(int numChildren) {
diff --git a/tests/tests/widget/src/android/widget/cts/util/ListScenario.java b/tests/tests/widget/src/android/widget/cts/util/ListScenario.java
index b61673c..c4d4199 100644
--- a/tests/tests/widget/src/android/widget/cts/util/ListScenario.java
+++ b/tests/tests/widget/src/android/widget/cts/util/ListScenario.java
@@ -79,10 +79,6 @@
         return mListView;
     }
 
-    protected int getScreenHeight() {
-        return mScreenHeight;
-    }
-
     /**
      * Return whether the item at position is selectable (i.e is a separator).
      * (external users can access this info using the adapter)
@@ -288,15 +284,6 @@
         setClickedPosition(position);
     }
 
-    /**
-     * Override this if you want to know when something has been long clicked (perhaps
-     * more importantly, that {@link android.widget.AdapterView.OnItemLongClickListener} has
-     * been triggered).
-     */
-    protected void positionLongClicked(int position) {
-        setLongClickedPosition(position);
-    }
-
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -353,11 +340,13 @@
             }
         });
 
-        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-            public void onItemClick(AdapterView parent, View v, int position, long id) {
-                positionClicked(position);
-            }
-        });
+        if (shouldRegisterItemClickListener()) {
+            mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+                public void onItemClick(AdapterView parent, View v, int position, long id) {
+                    positionClicked(position);
+                }
+            });
+        }
 
         // set the fading edge length porportionally to the screen
         // height for test stability
@@ -404,25 +393,11 @@
     }
 
     /**
-     * Returns the LinearLayout containing the ListView in this scenario.
-     *
-     * @return The LinearLayout in which the ListView is held.
+     * Override to return false if you don't want the activity to register a default item click
+     * listener that redirects clicks to {@link #positionClicked(int)}.
      */
-    protected LinearLayout getListViewContainer() {
-        return mLinearLayout;
-    }
-
-    /**
-     * Attaches a long press listener. You can find out which views were clicked by calling
-     * {@link #getLongClickedPosition()}.
-     */
-    public void enableLongPress() {
-        mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
-            public boolean onItemLongClick(AdapterView parent, View v, int position, long id) {
-                positionLongClicked(position);
-                return true;
-            }
-        });
+    protected boolean shouldRegisterItemClickListener() {
+        return true;
     }
 
     /**
diff --git a/tests/tests/widget/src/android/widget/cts/util/TestUtils.java b/tests/tests/widget/src/android/widget/cts/util/TestUtils.java
index 8d8f573..97d90f6 100644
--- a/tests/tests/widget/src/android/widget/cts/util/TestUtils.java
+++ b/tests/tests/widget/src/android/widget/cts/util/TestUtils.java
@@ -16,20 +16,36 @@
 
 package android.widget.cts.util;
 
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.support.annotation.ColorInt;
-import android.support.annotation.NonNull;
 import android.util.Pair;
+import android.util.SparseBooleanArray;
 import android.view.View;
 import android.view.ViewParent;
+import android.widget.TextView;
+
 import junit.framework.Assert;
 
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.argThat;
+
 public class TestUtils {
     /**
      * This method takes a view and returns a single bitmap that is the layered combination
@@ -100,7 +116,8 @@
     }
 
     /**
-     * Checks whether all the pixels in the specified View are of the same specified color.
+     * Checks whether all the pixels in the specified of the {@link View} are
+     * filled with the specific color.
      *
      * In case there is a color mismatch, the behavior of this method depends on the
      * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
@@ -109,7 +126,26 @@
      */
     public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull View view,
             @ColorInt int color, int allowedComponentVariance, boolean throwExceptionIfFails) {
+        assertRegionPixelsOfColor(failMessagePrefix, view,
+                new Rect(0, 0, view.getWidth(), view.getHeight()),
+                color, allowedComponentVariance, throwExceptionIfFails);
+    }
+
+    /**
+     * Checks whether all the pixels in the specific rectangular region of the {@link View} are
+     * filled with the specific color.
+     *
+     * In case there is a color mismatch, the behavior of this method depends on the
+     * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
+     * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
+     * <code>Assert.fail</code> with detailed description of the mismatch.
+     */
+    public static void assertRegionPixelsOfColor(String failMessagePrefix, @NonNull View view,
+            @NonNull Rect region, @ColorInt int color, int allowedComponentVariance,
+            boolean throwExceptionIfFails) {
         // Create a bitmap
+        final int viewWidth = view.getWidth();
+        final int viewHeight = view.getHeight();
         Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
                 Bitmap.Config.ARGB_8888);
         // Create a canvas that wraps the bitmap
@@ -118,7 +154,7 @@
         view.draw(canvas);
 
         try {
-            assertAllPixelsOfColor(failMessagePrefix, bitmap, view.getWidth(), view.getHeight(),
+            assertAllPixelsOfColor(failMessagePrefix, bitmap, region,
                     color, allowedComponentVariance, throwExceptionIfFails);
         } finally {
             bitmap.recycle();
@@ -126,7 +162,8 @@
     }
 
     /**
-     * Checks whether all the pixels in the specified drawable are of the same specified color.
+     * Checks whether all the pixels in the specified {@link Drawable} are filled with the specific
+     * color.
      *
      * In case there is a color mismatch, the behavior of this method depends on the
      * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
@@ -136,20 +173,25 @@
     public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
             int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
             int allowedComponentVariance, boolean throwExceptionIfFails) {
-            // Create a bitmap
-            Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight,
-                    Bitmap.Config.ARGB_8888);
-            // Create a canvas that wraps the bitmap
-            Canvas canvas = new Canvas(bitmap);
-            if (callSetBounds) {
-                // Configure the drawable to have bounds that match the passed size
-                drawable.setBounds(0, 0, drawableWidth, drawableHeight);
-            }
-            // And ask the drawable to draw itself to the canvas / bitmap
-            drawable.draw(canvas);
+        // Create a bitmap
+        Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight,
+                Bitmap.Config.ARGB_8888);
+        // Create a canvas that wraps the bitmap
+        Canvas canvas = new Canvas(bitmap);
+        if (callSetBounds) {
+            // Configure the drawable to have bounds that match the passed size
+            drawable.setBounds(0, 0, drawableWidth, drawableHeight);
+        } else {
+            // Query the current bounds of the drawable for translation
+            Rect drawableBounds = drawable.getBounds();
+            canvas.translate(-drawableBounds.left, -drawableBounds.top);
+        }
+        // And ask the drawable to draw itself to the canvas / bitmap
+        drawable.draw(canvas);
 
         try {
-            assertAllPixelsOfColor(failMessagePrefix, bitmap, drawableWidth, drawableHeight, color,
+            assertAllPixelsOfColor(failMessagePrefix, bitmap,
+                    new Rect(0, 0, drawableWidth, drawableHeight), color,
                     allowedComponentVariance, throwExceptionIfFails);
         } finally {
             bitmap.recycle();
@@ -157,49 +199,39 @@
     }
 
     /**
-     * Checks whether all the pixels in the specified bitmap are of the same specified color.
+     * Checks whether all the pixels in the specific rectangular region of the bitmap are filled
+     * with the specific color.
      *
      * In case there is a color mismatch, the behavior of this method depends on the
      * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
      * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
      * <code>Assert.fail</code> with detailed description of the mismatch.
      */
-    public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Bitmap bitmap,
-            int bitmapWidth, int bitmapHeight, @ColorInt int color,
-            int allowedComponentVariance, boolean throwExceptionIfFails) {
-            int[] rowPixels = new int[bitmapWidth];
-        for (int row = 0; row < bitmapHeight; row++) {
+    private static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Bitmap bitmap,
+            @NonNull Rect region, @ColorInt int color, int allowedComponentVariance,
+            boolean throwExceptionIfFails) {
+        final int bitmapWidth = bitmap.getWidth();
+        final int bitmapHeight = bitmap.getHeight();
+        final int[] rowPixels = new int[bitmapWidth];
+
+        final int startRow = region.top;
+        final int endRow = region.bottom;
+        final int startColumn = region.left;
+        final int endColumn = region.right;
+
+        for (int row = startRow; row < endRow; row++) {
             bitmap.getPixels(rowPixels, 0, bitmapWidth, 0, row, bitmapWidth, 1);
-            for (int column = 0; column < bitmapWidth; column++) {
-                int sourceAlpha = Color.alpha(rowPixels[column]);
-                int sourceRed = Color.red(rowPixels[column]);
-                int sourceGreen = Color.green(rowPixels[column]);
-                int sourceBlue = Color.blue(rowPixels[column]);
-
-                int expectedAlpha = Color.alpha(color);
-                int expectedRed = Color.red(color);
-                int expectedGreen = Color.green(color);
-                int expectedBlue = Color.blue(color);
-
-                int varianceAlpha = Math.abs(sourceAlpha - expectedAlpha);
-                int varianceRed = Math.abs(sourceRed - expectedRed);
-                int varianceGreen = Math.abs(sourceGreen - expectedGreen);
-                int varianceBlue = Math.abs(sourceBlue - expectedBlue);
-
-                boolean isColorMatch = (varianceAlpha <= allowedComponentVariance)
-                        && (varianceRed <= allowedComponentVariance)
-                        && (varianceGreen <= allowedComponentVariance)
-                        && (varianceBlue <= allowedComponentVariance);
-
-                if (!isColorMatch) {
+            for (int column = startColumn; column < endColumn; column++) {
+                @ColorInt int colorAtCurrPixel = rowPixels[column];
+                if (!areColorsTheSameWithTolerance(color, colorAtCurrPixel,
+                        allowedComponentVariance)) {
                     String mismatchDescription = failMessagePrefix
-                            + ": expected all drawable colors to be ["
-                            + expectedAlpha + "," + expectedRed + ","
-                            + expectedGreen + "," + expectedBlue
-                            + "] but at position (" + row + "," + column + ") out of ("
-                            + bitmapWidth + "," + bitmapHeight + ") found ["
-                            + sourceAlpha + "," + sourceRed + ","
-                            + sourceGreen + "," + sourceBlue + "]";
+                            + ": expected all bitmap colors in rectangle [l="
+                            + startColumn + ", t=" + startRow + ", r=" + endColumn
+                            + ", b=" + endRow + "] to be " + formatColorToHex(color)
+                            + " but at position (" + row + "," + column + ") out of ("
+                            + bitmapWidth + "," + bitmapHeight + ") found "
+                            + formatColorToHex(colorAtCurrPixel);
                     if (throwExceptionIfFails) {
                         throw new RuntimeException(mismatchDescription);
                     } else {
@@ -209,4 +241,247 @@
             }
         }
     }
+
+    /**
+     * Checks whether the center pixel in the specified bitmap is of the same specified color.
+     *
+     * In case there is a color mismatch, the behavior of this method depends on the
+     * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
+     * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
+     * <code>Assert.fail</code> with detailed description of the mismatch.
+     */
+    public static void assertCenterPixelOfColor(String failMessagePrefix, @NonNull Bitmap bitmap,
+            @ColorInt int color,
+            int allowedComponentVariance, boolean throwExceptionIfFails) {
+        final int centerX = bitmap.getWidth() / 2;
+        final int centerY = bitmap.getHeight() / 2;
+        final @ColorInt int colorAtCenterPixel = bitmap.getPixel(centerX, centerY);
+        if (!areColorsTheSameWithTolerance(color, colorAtCenterPixel,
+                allowedComponentVariance)) {
+            String mismatchDescription = failMessagePrefix
+                    + ": expected all drawable colors to be "
+                    + formatColorToHex(color)
+                    + " but at position (" + centerX + "," + centerY + ") out of ("
+                    + bitmap.getWidth() + "," + bitmap.getHeight() + ") found"
+                    + formatColorToHex(colorAtCenterPixel);
+            if (throwExceptionIfFails) {
+                throw new RuntimeException(mismatchDescription);
+            } else {
+                Assert.fail(mismatchDescription);
+            }
+        }
+    }
+
+    /**
+     * Formats the passed integer-packed color into the #AARRGGBB format.
+     */
+    public static String formatColorToHex(@ColorInt int color) {
+        return String.format("#%08X", (0xFFFFFFFF & color));
+    }
+
+    /**
+     * Compares two integer-packed colors to be equal, each component within the specified
+     * allowed variance. Returns <code>true</code> if the two colors are sufficiently equal
+     * and <code>false</code> otherwise.
+     */
+    private static boolean areColorsTheSameWithTolerance(@ColorInt int expectedColor,
+            @ColorInt int actualColor, int allowedComponentVariance) {
+        int sourceAlpha = Color.alpha(actualColor);
+        int sourceRed = Color.red(actualColor);
+        int sourceGreen = Color.green(actualColor);
+        int sourceBlue = Color.blue(actualColor);
+
+        int expectedAlpha = Color.alpha(expectedColor);
+        int expectedRed = Color.red(expectedColor);
+        int expectedGreen = Color.green(expectedColor);
+        int expectedBlue = Color.blue(expectedColor);
+
+        int varianceAlpha = Math.abs(sourceAlpha - expectedAlpha);
+        int varianceRed = Math.abs(sourceRed - expectedRed);
+        int varianceGreen = Math.abs(sourceGreen - expectedGreen);
+        int varianceBlue = Math.abs(sourceBlue - expectedBlue);
+
+        boolean isColorMatch = (varianceAlpha <= allowedComponentVariance)
+                && (varianceRed <= allowedComponentVariance)
+                && (varianceGreen <= allowedComponentVariance)
+                && (varianceBlue <= allowedComponentVariance);
+
+        return isColorMatch;
+    }
+
+    /**
+     * Composite two potentially translucent colors over each other and returns the result.
+     */
+    public static int compositeColors(@ColorInt int foreground, @ColorInt int background) {
+        int bgAlpha = Color.alpha(background);
+        int fgAlpha = Color.alpha(foreground);
+        int a = compositeAlpha(fgAlpha, bgAlpha);
+
+        int r = compositeComponent(Color.red(foreground), fgAlpha,
+                Color.red(background), bgAlpha, a);
+        int g = compositeComponent(Color.green(foreground), fgAlpha,
+                Color.green(background), bgAlpha, a);
+        int b = compositeComponent(Color.blue(foreground), fgAlpha,
+                Color.blue(background), bgAlpha, a);
+
+        return Color.argb(a, r, g, b);
+    }
+
+    private static int compositeAlpha(int foregroundAlpha, int backgroundAlpha) {
+        return 0xFF - (((0xFF - backgroundAlpha) * (0xFF - foregroundAlpha)) / 0xFF);
+    }
+
+    private static int compositeComponent(int fgC, int fgA, int bgC, int bgA, int a) {
+        if (a == 0) return 0;
+        return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF);
+    }
+
+    public static ColorStateList colorStateListOf(final @ColorInt int color) {
+        return argThat(new BaseMatcher<ColorStateList>() {
+            @Override
+            public boolean matches(Object o) {
+                if (o instanceof ColorStateList) {
+                    final ColorStateList actual = (ColorStateList) o;
+                    return (actual.getColors().length == 1) && (actual.getDefaultColor() == color);
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("doesn't match " + formatColorToHex(color));
+            }
+        });
+    }
+
+    public static int dpToPx(Context context, int dp) {
+        final float density = context.getResources().getDisplayMetrics().density;
+        return (int) (dp * density + 0.5f);
+    }
+
+    private static String arrayToString(final long[] array) {
+        final StringBuffer buffer = new StringBuffer();
+        if (array == null) {
+            buffer.append("null");
+        } else {
+            buffer.append("[");
+            for (int i = 0; i < array.length; i++) {
+                if (i > 0) {
+                    buffer.append(", ");
+                }
+                buffer.append(array[i]);
+            }
+            buffer.append("]");
+        }
+        return buffer.toString();
+    }
+
+    public static void assertIdentical(final long[] expected, final long[] actual) {
+        if (!Arrays.equals(expected, actual)) {
+            Assert.fail("Expected " + arrayToString(expected) + ", actual "
+                    + arrayToString(actual));
+        }
+    }
+
+    public static void assertTrueValuesAtPositions(final long[] expectedIndexesForTrueValues,
+            final SparseBooleanArray array) {
+        if (array == null) {
+           if ((expectedIndexesForTrueValues != null)
+                   && (expectedIndexesForTrueValues.length > 0)) {
+               Assert.fail("Expected " + arrayToString(expectedIndexesForTrueValues)
+                    + ", actual [null]");
+           }
+           return;
+        }
+
+        final int totalValuesCount = array.size();
+        // "Convert" the input array into a long[] array that has indexes of true values
+        int trueValuesCount = 0;
+        for (int i = 0; i < totalValuesCount; i++) {
+            if (array.valueAt(i)) {
+                trueValuesCount++;
+            }
+        }
+
+        final long[] trueValuePositions = new long[trueValuesCount];
+        int position = 0;
+        for (int i = 0; i < totalValuesCount; i++) {
+            if (array.valueAt(i)) {
+                trueValuePositions[position++] = array.keyAt(i);
+            }
+        }
+
+        Arrays.sort(trueValuePositions);
+        assertIdentical(expectedIndexesForTrueValues, trueValuePositions);
+    }
+
+    public static Drawable getDrawable(Context context, @DrawableRes int resid) {
+        return context.getResources().getDrawable(resid);
+    }
+
+    public static Bitmap getBitmap(Context context, @DrawableRes int resid) {
+        return ((BitmapDrawable) getDrawable(context, resid)).getBitmap();
+    }
+
+    public static void verifyCompoundDrawables(@NonNull TextView textView,
+            @DrawableRes int expectedLeftDrawableId, @DrawableRes int expectedRightDrawableId,
+            @DrawableRes int expectedTopDrawableId, @DrawableRes int expectedBottomDrawableId) {
+        final Context context = textView.getContext();
+        final Drawable[] compoundDrawables = textView.getCompoundDrawables();
+        if (expectedLeftDrawableId < 0) {
+            assertNull(compoundDrawables[0]);
+        } else {
+            WidgetTestUtils.assertEquals(getBitmap(context, expectedLeftDrawableId),
+                    ((BitmapDrawable) compoundDrawables[0]).getBitmap());
+        }
+        if (expectedTopDrawableId < 0) {
+            assertNull(compoundDrawables[1]);
+        } else {
+            WidgetTestUtils.assertEquals(getBitmap(context, expectedTopDrawableId),
+                    ((BitmapDrawable) compoundDrawables[1]).getBitmap());
+        }
+        if (expectedRightDrawableId < 0) {
+            assertNull(compoundDrawables[2]);
+        } else {
+            WidgetTestUtils.assertEquals(getBitmap(context, expectedRightDrawableId),
+                    ((BitmapDrawable) compoundDrawables[2]).getBitmap());
+        }
+        if (expectedBottomDrawableId < 0) {
+            assertNull(compoundDrawables[3]);
+        } else {
+            WidgetTestUtils.assertEquals(getBitmap(context, expectedBottomDrawableId),
+                    ((BitmapDrawable) compoundDrawables[3]).getBitmap());
+        }
+    }
+
+    public static void verifyCompoundDrawablesRelative(@NonNull TextView textView,
+            @DrawableRes int expectedStartDrawableId, @DrawableRes int expectedEndDrawableId,
+            @DrawableRes int expectedTopDrawableId, @DrawableRes int expectedBottomDrawableId) {
+        final Context context = textView.getContext();
+        final Drawable[] compoundDrawablesRelative = textView.getCompoundDrawablesRelative();
+        if (expectedStartDrawableId < 0) {
+            assertNull(compoundDrawablesRelative[0]);
+        } else {
+            WidgetTestUtils.assertEquals(getBitmap(context, expectedStartDrawableId),
+                    ((BitmapDrawable) compoundDrawablesRelative[0]).getBitmap());
+        }
+        if (expectedTopDrawableId < 0) {
+            assertNull(compoundDrawablesRelative[1]);
+        } else {
+            WidgetTestUtils.assertEquals(getBitmap(context, expectedTopDrawableId),
+                    ((BitmapDrawable) compoundDrawablesRelative[1]).getBitmap());
+        }
+        if (expectedEndDrawableId < 0) {
+            assertNull(compoundDrawablesRelative[2]);
+        } else {
+            WidgetTestUtils.assertEquals(getBitmap(context, expectedEndDrawableId),
+                    ((BitmapDrawable) compoundDrawablesRelative[2]).getBitmap());
+        }
+        if (expectedBottomDrawableId < 0) {
+            assertNull(compoundDrawablesRelative[3]);
+        } else {
+            WidgetTestUtils.assertEquals(getBitmap(context, expectedBottomDrawableId),
+                    ((BitmapDrawable) compoundDrawablesRelative[3]).getBitmap());
+        }
+    }
 }
\ No newline at end of file
diff --git a/tests/tests/widget/src/android/widget/cts/util/TestUtilsMatchers.java b/tests/tests/widget/src/android/widget/cts/util/TestUtilsMatchers.java
new file mode 100644
index 0000000..3664bc4
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/util/TestUtilsMatchers.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.widget.cts.util;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+import java.util.List;
+
+public class TestUtilsMatchers {
+    /**
+     * Returns a matcher that matches lists of int values that are in ascending order.
+     */
+    public static Matcher<List<Integer>> inAscendingOrder() {
+        return new TypeSafeMatcher<List<Integer>>() {
+            private String mFailedDescription;
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText(mFailedDescription);
+            }
+
+            @Override
+            protected boolean matchesSafely(List<Integer> item) {
+                int itemCount = item.size();
+
+                if (itemCount >= 2) {
+                    for (int i = 0; i < itemCount - 1; i++) {
+                        int curr = item.get(i);
+                        int next = item.get(i + 1);
+
+                        if (curr > next) {
+                            mFailedDescription = "Values should increase between #" + i +
+                                    ":" + curr + " and #" + (i + 1) + ":" + next;
+                            return false;
+                        }
+                    }
+                }
+
+                return true;
+            }
+        };
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java b/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
deleted file mode 100644
index e9ef867..0000000
--- a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
+++ /dev/null
@@ -1,75 +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.widget.cts.util;
-
-import junit.framework.Assert;
-
-import android.app.Instrumentation;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnDrawListener;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Utilities for testing View behavior.
- */
-public class ViewTestUtils {
-
-    /**
-     * Runs the specified Runnable on the main thread and ensures that the
-     * specified View's tree is drawn before returning.
-     *
-     * @param instrumentation the instrumentation used to run the test
-     * @param view the view whose tree should be drawn before returning
-     * @param runner the runnable to run on the main thread, or {@code null} to
-     *               simply force invalidation and a draw pass
-     */
-    public static void runOnMainAndDrawSync(@NonNull Instrumentation instrumentation,
-            @NonNull final View view, @Nullable final Runnable runner) {
-        final CountDownLatch latch = new CountDownLatch(1);
-
-        instrumentation.runOnMainSync(() -> {
-            final ViewTreeObserver observer = view.getViewTreeObserver();
-            final OnDrawListener listener = new OnDrawListener() {
-                @Override
-                public void onDraw() {
-                    observer.removeOnDrawListener(this);
-                    view.post(() -> latch.countDown());
-                }
-            };
-
-            observer.addOnDrawListener(listener);
-
-            if (runner != null) {
-                runner.run();
-            } else {
-                view.invalidate();
-            }
-        });
-
-        try {
-            Assert.assertTrue("Expected draw pass occurred within 5 seconds",
-                    latch.await(5, TimeUnit.SECONDS));
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index e7b08cb..3e4b9dd 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -42,17 +42,6 @@
     <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetId" />
     <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetIds" />
 
-    <!-- b/21668302 -->
-    <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.AssistantContentViewTest#testAssistantContentViewDimens" />
-    <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.ExtraAssistDataTest#testAssistContentAndAssistData" />
-    <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.FocusChangeTest#testLayerCausesUnderlyingActivityToLoseFocus" />
-    <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.LargeViewHierarchyTest#testTextView" />
-    <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.ScreenshotTest#testBlueScreenshot" />
-    <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.ScreenshotTest#testGreenScreenshot" />
-    <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.ScreenshotTest#testRedScreenshot" />
-    <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.TextViewTest#testTextView" />
-    <option name="compatibility:exclude-filter" value="CtsAssistTestCases android.assist.cts.WebViewTest#testWebView" />
-
     <!-- b/23776099 -->
     <option name="compatibility:exclude-filter" value="CtsCallLogTestCases" />
 
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/Abi.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/Abi.java
deleted file mode 100644
index 926e14b..0000000
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/Abi.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.tradefed.testtype;
-
-import com.android.tradefed.testtype.IAbi;
-/**
- * A class representing an ABI.
- */
-public class Abi implements IAbi {
-
-    private String mName;
-    private String mBitness;
-
-    public Abi(String name, String bitness) {
-        mName = name;
-        mBitness = bitness;
-    }
-
-    @Override
-    public String getName() {
-        return mName;
-    }
-
-    @Override
-    public String getBitness() {
-        return mBitness;
-    }
-
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
index acd977e..c32f632 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
@@ -18,6 +18,7 @@
 import com.android.compatibility.common.util.AbiUtils;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.testtype.Abi;
 import com.android.tradefed.util.xml.AbstractXmlParser;
 
 import org.xml.sax.Attributes;
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java
index 29c1324..fce7604 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java
@@ -22,7 +22,6 @@
 import com.android.cts.tradefed.result.TestSummaryXmlTest;
 import com.android.cts.tradefed.result.TestTest;
 import com.android.cts.tradefed.result.TestLogTest;
-import com.android.cts.tradefed.testtype.Abi;
 import com.android.cts.tradefed.testtype.CtsTestTest;
 import com.android.cts.tradefed.testtype.DeqpTestRunnerTest;
 import com.android.cts.tradefed.testtype.GeeTestTest;
@@ -32,6 +31,7 @@
 import com.android.cts.tradefed.testtype.TestPackageXmlParserTest;
 import com.android.cts.tradefed.testtype.TestPlanTest;
 import com.android.cts.tradefed.testtype.WrappedGTestResultParserTest;
+import com.android.tradefed.testtype.Abi;
 import com.android.tradefed.testtype.IAbi;
 
 import junit.framework.Test;
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index f983b15..bd5fc90 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -522,15 +522,6 @@
           'android.alarmclock.cts.SetAlarmTest#testAll',
           'android.alarmclock.cts.SnoozeAlarmTest#testAll',
       ],
-      'android.assist' : [
-          'android.assist.cts.AssistantContentViewTest',
-          'android.assist.cts.ExtraAssistDataTest',
-          'android.assist.cts.FocusChangeTest',
-          'android.assist.cts.LargeViewHierarchyTest',
-          'android.assist.cts.ScreenshotTest',
-          'android.assist.cts.TextViewTest',
-          'android.assist.cts.WebViewTest',
-      ],
       'android.calllog' : [
           'android.calllog.cts.CallLogBackupTest#testSingleCallBackup',
       ],